From 32ead51e5a8d6abbc0b4bacb00192ddc72a9817a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 23 Apr 2024 12:43:49 -0400 Subject: [PATCH 001/658] Add material design icons to admin/settings views (#27780) Co-authored-by: Claire --- app/helpers/application_helper.rb | 8 ++++++++ app/javascript/styles/mastodon/admin.scss | 7 +++++++ .../account_warnings/_account_warning.html.haml | 2 +- app/views/admin/accounts/_remote_account.html.haml | 4 ++-- app/views/admin/accounts/index.html.haml | 6 +++--- app/views/admin/accounts/show.html.haml | 2 +- app/views/admin/custom_emojis/index.html.haml | 8 ++++---- app/views/admin/dashboard/index.html.haml | 8 ++++---- app/views/admin/email_domain_blocks/index.html.haml | 2 +- .../export_domain_blocks/_domain_block.html.haml | 2 +- .../admin/export_domain_blocks/import.html.haml | 2 +- .../admin/follow_recommendations/show.html.haml | 4 ++-- app/views/admin/instances/show.html.haml | 2 +- app/views/admin/invites/_invite.html.haml | 2 +- app/views/admin/ip_blocks/index.html.haml | 2 +- app/views/admin/relationships/index.html.haml | 4 ++-- app/views/admin/relays/_relay.html.haml | 4 ++-- app/views/admin/reports/_header_card.html.haml | 2 +- app/views/admin/reports/_status.html.haml | 2 +- app/views/admin/reports/actions/preview.html.haml | 2 +- app/views/admin/reports/show.html.haml | 4 ++-- app/views/admin/roles/_role.html.haml | 4 ++-- app/views/admin/settings/shared/_links.html.haml | 2 +- app/views/admin/status_edits/_status_edit.html.haml | 2 +- app/views/admin/statuses/index.html.haml | 4 ++-- app/views/admin/tags/show.html.haml | 12 ++++++------ app/views/admin/trends/links/index.html.haml | 10 +++++----- .../links/preview_card_providers/index.html.haml | 6 +++--- app/views/admin/trends/statuses/_status.html.haml | 2 +- app/views/admin/trends/statuses/index.html.haml | 8 ++++---- app/views/admin/trends/tags/_tag.html.haml | 2 +- app/views/admin/trends/tags/index.html.haml | 4 ++-- config/initializers/propshaft.rb | 4 ++++ 33 files changed, 79 insertions(+), 60 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 668afe7fde..4cf959f2d8 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -113,6 +113,14 @@ module ApplicationHelper content_tag(:i, nil, attributes.merge(class: class_names.join(' '))) end + def material_symbol(icon, attributes = {}) + inline_svg_tag( + "400-24px/#{icon}.svg", + class: %w(icon).concat(attributes[:class].to_s.split), + role: :img + ) + end + def check_icon inline_svg_tag 'check.svg' end diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index fadd77d13d..06a3b52021 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -10,6 +10,13 @@ $content-width: 840px; width: 100%; min-height: 100vh; + .icon { + width: 16px; + height: 16px; + vertical-align: middle; + margin: 0 2px; + } + .sidebar-wrapper { min-height: 100vh; overflow: hidden; diff --git a/app/views/admin/account_warnings/_account_warning.html.haml b/app/views/admin/account_warnings/_account_warning.html.haml index 5702e4f6d2..368e69e63e 100644 --- a/app/views/admin/account_warnings/_account_warning.html.haml +++ b/app/views/admin/account_warnings/_account_warning.html.haml @@ -2,7 +2,7 @@ .log-entry__header .log-entry__avatar .indicator-icon{ class: account_warning.overruled? ? 'success' : 'failure' } - = fa_icon 'warning' + = material_symbol 'warning' .log-entry__content .log-entry__title = t(account_warning.action, diff --git a/app/views/admin/accounts/_remote_account.html.haml b/app/views/admin/accounts/_remote_account.html.haml index 99996e1d46..6755af2496 100644 --- a/app/views/admin/accounts/_remote_account.html.haml +++ b/app/views/admin/accounts/_remote_account.html.haml @@ -2,14 +2,14 @@ %th= t('admin.accounts.inbox_url') %td = account.inbox_url - = fa_icon DeliveryFailureTracker.available?(account.inbox_url) ? 'check' : 'times' + = material_symbol DeliveryFailureTracker.available?(account.inbox_url) ? 'check' : 'close' %td = table_link_to 'search', domain_block.present? ? t('admin.domain_blocks.view') : t('admin.accounts.view_domain'), admin_instance_path(account.domain) %tr %th= t('admin.accounts.shared_inbox_url') %td = account.shared_inbox_url - = fa_icon DeliveryFailureTracker.available?(account.shared_inbox_url) ? 'check' : 'times' + = material_symbol DeliveryFailureTracker.available?(account.shared_inbox_url) ? 'check' : 'close' %td - if domain_block.nil? = table_link_to 'ban', t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: account.domain) diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index 0ca457f39e..01b072938d 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -53,19 +53,19 @@ = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - if @accounts.any?(&:user_pending?) - = f.button safe_join([fa_icon('check'), t('admin.accounts.approve')]), + = f.button safe_join([material_symbol('check'), t('admin.accounts.approve')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :approve, type: :submit - = f.button safe_join([fa_icon('times'), t('admin.accounts.reject')]), + = f.button safe_join([material_symbol('close'), t('admin.accounts.reject')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :reject, type: :submit - = f.button safe_join([fa_icon('lock'), t('admin.accounts.perform_full_suspension')]), + = f.button safe_join([material_symbol('lock'), t('admin.accounts.perform_full_suspension')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :suspend, diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index d380d807a3..41fcafa29d 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -20,7 +20,7 @@ %dd{ title: field.value, class: custom_field_classes(field) } - if field.verified? %span.verified__mark{ title: t('accounts.link_verified_on', date: l(field.verified_at)) } - = fa_icon 'check' + = material_symbol 'check' = prerender_custom_emojis(account_field_value_format(field, with_rel_me: false), account.emojis) - if account.note.present? diff --git a/app/views/admin/custom_emojis/index.html.haml b/app/views/admin/custom_emojis/index.html.haml index bea6a7cd21..e87dd41282 100644 --- a/app/views/admin/custom_emojis/index.html.haml +++ b/app/views/admin/custom_emojis/index.html.haml @@ -48,19 +48,19 @@ - if params[:local] == '1' = f.button safe_join([fa_icon('save'), t('generic.save_changes')]), name: :update, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } - = f.button safe_join([fa_icon('eye'), t('admin.custom_emojis.list')]), name: :list, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + = f.button safe_join([material_symbol('visibility'), t('admin.custom_emojis.list')]), name: :list, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } - = f.button safe_join([fa_icon('eye-slash'), t('admin.custom_emojis.unlist')]), name: :unlist, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + = f.button safe_join([material_symbol('visibility_off'), t('admin.custom_emojis.unlist')]), name: :unlist, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } = f.button safe_join([fa_icon('power-off'), t('admin.custom_emojis.enable')]), name: :enable, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } = f.button safe_join([fa_icon('power-off'), t('admin.custom_emojis.disable')]), name: :disable, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } - if can?(:destroy, :custom_emoji) - = f.button safe_join([fa_icon('times'), t('admin.custom_emojis.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + = f.button safe_join([material_symbol('close'), t('admin.custom_emojis.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } - if can?(:copy, :custom_emoji) && params[:local] != '1' - = f.button safe_join([fa_icon('copy'), t('admin.custom_emojis.copy')]), name: :copy, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + = f.button safe_join([material_symbol('content_copy'), t('admin.custom_emojis.copy')]), name: :copy, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } - if params[:local] == '1' .batch-table__form.simple_form diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 8a80992785..8430dd3c4f 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -57,19 +57,19 @@ .dashboard__item = link_to admin_reports_path, class: 'dashboard__quick-access' do %span= t('admin.dashboard.pending_reports_html', count: @pending_reports_count) - = fa_icon 'chevron-right fw' + = material_symbol 'chevron_right' = link_to admin_accounts_path(status: 'pending'), class: 'dashboard__quick-access' do %span= t('admin.dashboard.pending_users_html', count: @pending_users_count) - = fa_icon 'chevron-right fw' + = material_symbol 'chevron_right' = link_to admin_trends_tags_path(status: 'pending_review'), class: 'dashboard__quick-access' do %span= t('admin.dashboard.pending_tags_html', count: @pending_tags_count) - = fa_icon 'chevron-right fw' + = material_symbol 'chevron_right' = link_to admin_disputes_appeals_path(status: 'pending'), class: 'dashboard__quick-access' do %span= t('admin.dashboard.pending_appeals_html', count: @pending_appeals_count) - = fa_icon 'chevron-right fw' + = material_symbol 'chevron_right' .dashboard__item = react_admin_component :dimension, dimension: 'sources', diff --git a/app/views/admin/email_domain_blocks/index.html.haml b/app/views/admin/email_domain_blocks/index.html.haml index 59036f899f..684735c207 100644 --- a/app/views/admin/email_domain_blocks/index.html.haml +++ b/app/views/admin/email_domain_blocks/index.html.haml @@ -12,7 +12,7 @@ %label.batch-table__toolbar__select.batch-checkbox-all = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - = f.button safe_join([fa_icon('times'), t('admin.email_domain_blocks.delete')]), + = f.button safe_join([material_symbol('close'), t('admin.email_domain_blocks.delete')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :delete, diff --git a/app/views/admin/export_domain_blocks/_domain_block.html.haml b/app/views/admin/export_domain_blocks/_domain_block.html.haml index cdce4fd28a..79cc5595ca 100644 --- a/app/views/admin/export_domain_blocks/_domain_block.html.haml +++ b/app/views/admin/export_domain_blocks/_domain_block.html.haml @@ -23,5 +23,5 @@ = f.object.public_comment - if existing_relationships · - = fa_icon 'warning fw' + = material_symbol 'warning' = t('admin.export_domain_blocks.import.existing_relationships_warning') diff --git a/app/views/admin/export_domain_blocks/import.html.haml b/app/views/admin/export_domain_blocks/import.html.haml index 48016a9abe..52ffc3d465 100644 --- a/app/views/admin/export_domain_blocks/import.html.haml +++ b/app/views/admin/export_domain_blocks/import.html.haml @@ -12,7 +12,7 @@ %label.batch-table__toolbar__select.batch-checkbox-all = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - = f.button safe_join([fa_icon('copy'), t('admin.domain_blocks.import')]), + = f.button safe_join([material_symbol('content_copy'), t('admin.domain_blocks.import')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :save, diff --git a/app/views/admin/follow_recommendations/show.html.haml b/app/views/admin/follow_recommendations/show.html.haml index 9d23f9ba51..c8ad653a88 100644 --- a/app/views/admin/follow_recommendations/show.html.haml +++ b/app/views/admin/follow_recommendations/show.html.haml @@ -31,13 +31,13 @@ = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - if params[:status].blank? && can?(:suppress, :follow_recommendation) - = f.button safe_join([fa_icon('times'), t('admin.follow_recommendations.suppress')]), + = f.button safe_join([material_symbol('close'), t('admin.follow_recommendations.suppress')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :suppress, type: :submit - if params[:status] == 'suppressed' && can?(:unsuppress, :follow_recommendation) - = f.button safe_join([fa_icon('plus'), t('admin.follow_recommendations.unsuppress')]), + = f.button safe_join([material_symbol('add'), t('admin.follow_recommendations.unsuppress')]), class: 'table-action-link', name: :unsuppress, type: :submit diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml index 5bf4e899f3..d916203d0c 100644 --- a/app/views/admin/instances/show.html.haml +++ b/app/views/admin/instances/show.html.haml @@ -9,7 +9,7 @@ - if @instance.persisted? %p - = fa_icon 'info fw' + = material_symbol 'info' = t('admin.instances.totals_time_period_hint_html') .dashboard diff --git a/app/views/admin/invites/_invite.html.haml b/app/views/admin/invites/_invite.html.haml index e6ad9de34c..f9cd6003f3 100644 --- a/app/views/admin/invites/_invite.html.haml +++ b/app/views/admin/invites/_invite.html.haml @@ -12,7 +12,7 @@ - if invite.valid_for_use? %td - = fa_icon 'user fw' + = material_symbol 'person' = invite.uses = " / #{invite.max_uses}" unless invite.max_uses.nil? %td diff --git a/app/views/admin/ip_blocks/index.html.haml b/app/views/admin/ip_blocks/index.html.haml index f1d2b3dc47..9eba6c68ff 100644 --- a/app/views/admin/ip_blocks/index.html.haml +++ b/app/views/admin/ip_blocks/index.html.haml @@ -14,7 +14,7 @@ = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - if can?(:destroy, :ip_block) - = f.button safe_join([fa_icon('times'), t('admin.ip_blocks.delete')]), + = f.button safe_join([material_symbol('close'), t('admin.ip_blocks.delete')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :delete, diff --git a/app/views/admin/relationships/index.html.haml b/app/views/admin/relationships/index.html.haml index 8260430d80..c2daefb424 100644 --- a/app/views/admin/relationships/index.html.haml +++ b/app/views/admin/relationships/index.html.haml @@ -19,7 +19,7 @@ .back-link = link_to admin_account_path(@account.id) do - = fa_icon 'chevron-left fw' + = material_symbol 'chevron_left' = t('admin.statuses.back_to_account') %hr.spacer/ @@ -30,7 +30,7 @@ %label.batch-table__toolbar__select.batch-checkbox-all = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - = f.button safe_join([fa_icon('lock'), t('admin.accounts.perform_full_suspension')]), + = f.button safe_join([material_symbol('lock'), t('admin.accounts.perform_full_suspension')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :suspend, diff --git a/app/views/admin/relays/_relay.html.haml b/app/views/admin/relays/_relay.html.haml index f1dd2b2dd1..0960124ccf 100644 --- a/app/views/admin/relays/_relay.html.haml +++ b/app/views/admin/relays/_relay.html.haml @@ -4,7 +4,7 @@ %td - if relay.accepted? %span.positive-hint - = fa_icon('check') + = material_symbol('check')   = t 'admin.relays.enabled' - elsif relay.pending? @@ -13,7 +13,7 @@ = t 'admin.relays.pending' - else %span.negative-hint - = fa_icon('times') + = material_symbol('close')   = t 'admin.relays.disabled' %td diff --git a/app/views/admin/reports/_header_card.html.haml b/app/views/admin/reports/_header_card.html.haml index e90e3f9c90..52e62b4499 100644 --- a/app/views/admin/reports/_header_card.html.haml +++ b/app/views/admin/reports/_header_card.html.haml @@ -16,7 +16,7 @@ %strong.emojify.p-name= display_name(report.target_account, custom_emojify: true) %span = acct(report.target_account) - = fa_icon('lock') if report.target_account.locked? + = material_symbol('lock') if report.target_account.locked? - if report.target_account.note.present? .account-card__bio.emojify = prerender_custom_emojis(account_bio_format(report.target_account), report.target_account.emojis) diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml index 3775a1101c..66820f0a6e 100644 --- a/app/views/admin/reports/_status.html.haml +++ b/app/views/admin/reports/_status.html.haml @@ -37,5 +37,5 @@ = t("statuses.visibilities.#{status.visibility}") - if status.proper.sensitive? · - = fa_icon('eye-slash fw') + = material_symbol('visibility_off') = t('stream_entries.sensitive_content') diff --git a/app/views/admin/reports/actions/preview.html.haml b/app/views/admin/reports/actions/preview.html.haml index 8634bb215c..7a737d4f72 100644 --- a/app/views/admin/reports/actions/preview.html.haml +++ b/app/views/admin/reports/actions/preview.html.haml @@ -58,7 +58,7 @@ - status.ordered_media_attachments.each do |media_attachment| %abbr{ title: media_attachment.description } - = fa_icon 'link' + = material_symbol 'link' = media_attachment.file_file_name .strike-card__statuses-list__item__meta = link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank', rel: 'noopener noreferrer' do diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index e37fa2590a..c880021cff 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -41,7 +41,7 @@ %p = t 'admin.reports.statuses_description_html' — - = link_to safe_join([fa_icon('plus'), t('admin.reports.add_to_report')]), + = link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]), admin_account_statuses_path(@report.target_account_id, report_id: @report.id), class: 'table-action-link' @@ -52,7 +52,7 @@ = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - if !@statuses.empty? && @report.unresolved? - = f.button safe_join([fa_icon('times'), t('admin.statuses.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit + = f.button safe_join([material_symbol('close'), t('admin.statuses.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit .batch-table__body - if @statuses.empty? = nothing_here 'nothing-here--under-tabs' diff --git a/app/views/admin/roles/_role.html.haml b/app/views/admin/roles/_role.html.haml index d6c6b62c81..fd37644c83 100644 --- a/app/views/admin/roles/_role.html.haml +++ b/app/views/admin/roles/_role.html.haml @@ -2,7 +2,7 @@ - if can?(:update, role) = link_to edit_admin_role_path(role), class: 'announcements-list__item__title' do %span.user-role{ class: "user-role-#{role.id}" } - = fa_icon 'users fw' + = material_symbol 'group' - if role.everyone? = t('admin.roles.everyone') @@ -11,7 +11,7 @@ - else %span.announcements-list__item__title %span.user-role{ class: "user-role-#{role.id}" } - = fa_icon 'users fw' + = material_symbol 'group' - if role.everyone? = t('admin.roles.everyone') diff --git a/app/views/admin/settings/shared/_links.html.haml b/app/views/admin/settings/shared/_links.html.haml index d8b697592a..8b0678d4c9 100644 --- a/app/views/admin/settings/shared/_links.html.haml +++ b/app/views/admin/settings/shared/_links.html.haml @@ -3,7 +3,7 @@ :ruby primary.item :branding, safe_join([fa_icon('pencil fw'), t('admin.settings.branding.title')]), admin_settings_branding_path primary.item :about, safe_join([fa_icon('file-text fw'), t('admin.settings.about.title')]), admin_settings_about_path - primary.item :registrations, safe_join([fa_icon('users fw'), t('admin.settings.registrations.title')]), admin_settings_registrations_path + primary.item :registrations, safe_join([material_symbol('group'), t('admin.settings.registrations.title')]), admin_settings_registrations_path primary.item :discovery, safe_join([fa_icon('search fw'), t('admin.settings.discovery.title')]), admin_settings_discovery_path primary.item :content_retention, safe_join([fa_icon('history fw'), t('admin.settings.content_retention.title')]), admin_settings_content_retention_path primary.item :appearance, safe_join([fa_icon('desktop fw'), t('admin.settings.appearance.title')]), admin_settings_appearance_path diff --git a/app/views/admin/status_edits/_status_edit.html.haml b/app/views/admin/status_edits/_status_edit.html.haml index 7254777213..0bec0159ee 100644 --- a/app/views/admin/status_edits/_status_edit.html.haml +++ b/app/views/admin/status_edits/_status_edit.html.haml @@ -26,5 +26,5 @@ - if status_edit.sensitive? · - = fa_icon('eye-slash fw') + = material_symbol('visibility_off') = t('stream_entries.sensitive_content') diff --git a/app/views/admin/statuses/index.html.haml b/app/views/admin/statuses/index.html.haml index 33a41bd365..a41a6332dd 100644 --- a/app/views/admin/statuses/index.html.haml +++ b/app/views/admin/statuses/index.html.haml @@ -12,11 +12,11 @@ .back-link - if params[:report_id] = link_to admin_report_path(params[:report_id].to_i) do - = fa_icon 'chevron-left fw' + = material_symbol 'chevron_left' = t('admin.statuses.back_to_report') - else = link_to admin_account_path(@account.id) do - = fa_icon 'chevron-left fw' + = material_symbol 'chevron_left' = t('admin.statuses.back_to_account') %hr.spacer/ diff --git a/app/views/admin/tags/show.html.haml b/app/views/admin/tags/show.html.haml index 2e4424bec6..f2d87b54b0 100644 --- a/app/views/admin/tags/show.html.haml +++ b/app/views/admin/tags/show.html.haml @@ -52,26 +52,26 @@ = link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.usable? ? 'positive' : 'negative'] do - if @tag.usable? %span= t('admin.trends.tags.usable') - = fa_icon 'check fw' + = material_symbol 'check' - else %span= t('admin.trends.tags.not_usable') - = fa_icon 'lock fw' + = material_symbol 'lock' = link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.trendable? ? 'positive' : 'negative'] do - if @tag.trendable? %span= t('admin.trends.tags.trendable') - = fa_icon 'check fw' + = material_symbol 'check' - else %span= t('admin.trends.tags.not_trendable') - = fa_icon 'lock fw' + = material_symbol 'lock' = link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.listable? ? 'positive' : 'negative'] do - if @tag.listable? %span= t('admin.trends.tags.listable') - = fa_icon 'check fw' + = material_symbol 'check' - else %span= t('admin.trends.tags.not_listable') - = fa_icon 'lock fw' + = material_symbol 'lock' %hr.spacer/ diff --git a/app/views/admin/trends/links/index.html.haml b/app/views/admin/trends/links/index.html.haml index 965d2b2e56..c503b2d396 100644 --- a/app/views/admin/trends/links/index.html.haml +++ b/app/views/admin/trends/links/index.html.haml @@ -24,7 +24,7 @@ .back-link = link_to admin_trends_links_preview_card_providers_path do = t('admin.trends.preview_card_providers.title') - = fa_icon 'chevron-right fw' + = material_symbol 'chevron_right' = form_for(@form, url: batch_admin_trends_links_path) do |f| = hidden_field_tag :page, params[:page] || 1 @@ -37,22 +37,22 @@ %label.batch-table__toolbar__select.batch-checkbox-all = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - = f.button safe_join([fa_icon('check'), t('admin.trends.links.allow')]), + = f.button safe_join([material_symbol('check'), t('admin.trends.links.allow')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :approve, type: :submit - = f.button safe_join([fa_icon('check'), t('admin.trends.links.allow_provider')]), + = f.button safe_join([material_symbol('check'), t('admin.trends.links.allow_provider')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :approve_providers, type: :submit - = f.button safe_join([fa_icon('times'), t('admin.trends.links.disallow')]), + = f.button safe_join([material_symbol('close'), t('admin.trends.links.disallow')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :reject, type: :submit - = f.button safe_join([fa_icon('times'), t('admin.trends.links.disallow_provider')]), + = f.button safe_join([material_symbol('close'), t('admin.trends.links.disallow_provider')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :reject_providers, diff --git a/app/views/admin/trends/links/preview_card_providers/index.html.haml b/app/views/admin/trends/links/preview_card_providers/index.html.haml index c91822fb74..706c607010 100644 --- a/app/views/admin/trends/links/preview_card_providers/index.html.haml +++ b/app/views/admin/trends/links/preview_card_providers/index.html.haml @@ -15,7 +15,7 @@ %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{PreviewCardProvider.pending_review.count})"], ' '), status: 'pending_review' .back-link = link_to admin_trends_links_path do - = fa_icon 'chevron-left fw' + = material_symbol 'chevron_left' = t('admin.trends.links.title') %hr.spacer/ @@ -31,12 +31,12 @@ %label.batch-table__toolbar__select.batch-checkbox-all = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - = f.button safe_join([fa_icon('check'), t('admin.trends.allow')]), + = f.button safe_join([material_symbol('check'), t('admin.trends.allow')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :approve, type: :submit - = f.button safe_join([fa_icon('times'), t('admin.trends.disallow')]), + = f.button safe_join([material_symbol('close'), t('admin.trends.disallow')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :reject, diff --git a/app/views/admin/trends/statuses/_status.html.haml b/app/views/admin/trends/statuses/_status.html.haml index 095f3f2187..09547ff036 100644 --- a/app/views/admin/trends/statuses/_status.html.haml +++ b/app/views/admin/trends/statuses/_status.html.haml @@ -11,7 +11,7 @@ - status.ordered_media_attachments.each do |media_attachment| %abbr{ title: media_attachment.description } - = fa_icon 'link' + = material_symbol 'link' = media_attachment.file_file_name = t 'admin.trends.statuses.shared_by', diff --git a/app/views/admin/trends/statuses/index.html.haml b/app/views/admin/trends/statuses/index.html.haml index 0891d15fcf..66151ad31e 100644 --- a/app/views/admin/trends/statuses/index.html.haml +++ b/app/views/admin/trends/statuses/index.html.haml @@ -31,22 +31,22 @@ %label.batch-table__toolbar__select.batch-checkbox-all = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - = f.button safe_join([fa_icon('check'), t('admin.trends.statuses.allow')]), + = f.button safe_join([material_symbol('check'), t('admin.trends.statuses.allow')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :approve, type: :submit - = f.button safe_join([fa_icon('check'), t('admin.trends.statuses.allow_account')]), + = f.button safe_join([material_symbol('check'), t('admin.trends.statuses.allow_account')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :approve_accounts, type: :submit - = f.button safe_join([fa_icon('times'), t('admin.trends.statuses.disallow')]), + = f.button safe_join([material_symbol('close'), t('admin.trends.statuses.disallow')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :reject, type: :submit - = f.button safe_join([fa_icon('times'), t('admin.trends.statuses.disallow_account')]), + = f.button safe_join([material_symbol('close'), t('admin.trends.statuses.disallow_account')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :reject_accounts, diff --git a/app/views/admin/trends/tags/_tag.html.haml b/app/views/admin/trends/tags/_tag.html.haml index 70c7d8dbd4..8cc0d713b9 100644 --- a/app/views/admin/trends/tags/_tag.html.haml +++ b/app/views/admin/trends/tags/_tag.html.haml @@ -5,7 +5,7 @@ .batch-table__row__content.pending-account .pending-account__header = link_to admin_tag_path(tag.id) do - = fa_icon 'hashtag' + = material_symbol 'tag' = tag.display_name %br/ diff --git a/app/views/admin/trends/tags/index.html.haml b/app/views/admin/trends/tags/index.html.haml index effde7b0ec..655955f7f6 100644 --- a/app/views/admin/trends/tags/index.html.haml +++ b/app/views/admin/trends/tags/index.html.haml @@ -25,12 +25,12 @@ %label.batch-table__toolbar__select.batch-checkbox-all = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - = f.button safe_join([fa_icon('check'), t('admin.trends.allow')]), + = f.button safe_join([material_symbol('check'), t('admin.trends.allow')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :approve, type: :submit - = f.button safe_join([fa_icon('times'), t('admin.trends.disallow')]), + = f.button safe_join([material_symbol('close'), t('admin.trends.disallow')]), class: 'table-action-link', data: { confirm: t('admin.reports.are_you_sure') }, name: :reject, diff --git a/config/initializers/propshaft.rb b/config/initializers/propshaft.rb index 6cf368d5b7..eff7ec90b8 100644 --- a/config/initializers/propshaft.rb +++ b/config/initializers/propshaft.rb @@ -1,3 +1,7 @@ # frozen_string_literal: true +# SVG icons Rails.application.config.assets.paths << Rails.root.join('app', 'javascript', 'images') + +# Material Design icons +Rails.application.config.assets.paths << Rails.root.join('app', 'javascript', 'material-icons') From 3f6887557b23d363e7f8f18518db4447739d64bb Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 23 Apr 2024 12:45:12 -0400 Subject: [PATCH 002/658] Move JS source from `packs` to `entrypoints` (#30037) --- app/javascript/{packs => entrypoints}/admin.tsx | 0 app/javascript/{packs => entrypoints}/application.js | 0 app/javascript/{packs => entrypoints}/error.js | 0 app/javascript/{packs => entrypoints}/inert.js | 0 app/javascript/{packs => entrypoints}/mailer.js | 0 app/javascript/{packs => entrypoints}/public-path.js | 0 app/javascript/{packs => entrypoints}/public.tsx | 0 .../{packs => entrypoints}/remote_interaction_helper.ts | 0 app/javascript/{packs => entrypoints}/share.jsx | 0 app/javascript/{packs => entrypoints}/sign_up.js | 0 .../{packs => entrypoints}/two_factor_authentication.js | 0 config/webpacker.yml | 2 +- tsconfig.json | 2 +- 13 files changed, 2 insertions(+), 2 deletions(-) rename app/javascript/{packs => entrypoints}/admin.tsx (100%) rename app/javascript/{packs => entrypoints}/application.js (100%) rename app/javascript/{packs => entrypoints}/error.js (100%) rename app/javascript/{packs => entrypoints}/inert.js (100%) rename app/javascript/{packs => entrypoints}/mailer.js (100%) rename app/javascript/{packs => entrypoints}/public-path.js (100%) rename app/javascript/{packs => entrypoints}/public.tsx (100%) rename app/javascript/{packs => entrypoints}/remote_interaction_helper.ts (100%) rename app/javascript/{packs => entrypoints}/share.jsx (100%) rename app/javascript/{packs => entrypoints}/sign_up.js (100%) rename app/javascript/{packs => entrypoints}/two_factor_authentication.js (100%) diff --git a/app/javascript/packs/admin.tsx b/app/javascript/entrypoints/admin.tsx similarity index 100% rename from app/javascript/packs/admin.tsx rename to app/javascript/entrypoints/admin.tsx diff --git a/app/javascript/packs/application.js b/app/javascript/entrypoints/application.js similarity index 100% rename from app/javascript/packs/application.js rename to app/javascript/entrypoints/application.js diff --git a/app/javascript/packs/error.js b/app/javascript/entrypoints/error.js similarity index 100% rename from app/javascript/packs/error.js rename to app/javascript/entrypoints/error.js diff --git a/app/javascript/packs/inert.js b/app/javascript/entrypoints/inert.js similarity index 100% rename from app/javascript/packs/inert.js rename to app/javascript/entrypoints/inert.js diff --git a/app/javascript/packs/mailer.js b/app/javascript/entrypoints/mailer.js similarity index 100% rename from app/javascript/packs/mailer.js rename to app/javascript/entrypoints/mailer.js diff --git a/app/javascript/packs/public-path.js b/app/javascript/entrypoints/public-path.js similarity index 100% rename from app/javascript/packs/public-path.js rename to app/javascript/entrypoints/public-path.js diff --git a/app/javascript/packs/public.tsx b/app/javascript/entrypoints/public.tsx similarity index 100% rename from app/javascript/packs/public.tsx rename to app/javascript/entrypoints/public.tsx diff --git a/app/javascript/packs/remote_interaction_helper.ts b/app/javascript/entrypoints/remote_interaction_helper.ts similarity index 100% rename from app/javascript/packs/remote_interaction_helper.ts rename to app/javascript/entrypoints/remote_interaction_helper.ts diff --git a/app/javascript/packs/share.jsx b/app/javascript/entrypoints/share.jsx similarity index 100% rename from app/javascript/packs/share.jsx rename to app/javascript/entrypoints/share.jsx diff --git a/app/javascript/packs/sign_up.js b/app/javascript/entrypoints/sign_up.js similarity index 100% rename from app/javascript/packs/sign_up.js rename to app/javascript/entrypoints/sign_up.js diff --git a/app/javascript/packs/two_factor_authentication.js b/app/javascript/entrypoints/two_factor_authentication.js similarity index 100% rename from app/javascript/packs/two_factor_authentication.js rename to app/javascript/entrypoints/two_factor_authentication.js diff --git a/config/webpacker.yml b/config/webpacker.yml index f8462e53a0..e07f577c5e 100644 --- a/config/webpacker.yml +++ b/config/webpacker.yml @@ -2,7 +2,7 @@ default: &default source_path: app/javascript - source_entry_path: packs + source_entry_path: entrypoints public_root_path: public public_output_path: packs cache_path: tmp/cache/webpacker diff --git a/tsconfig.json b/tsconfig.json index a193ea35f2..7010dda1fc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,7 @@ }, "include": [ "app/javascript/mastodon", - "app/javascript/packs", + "app/javascript/entrypoints", "app/javascript/types" ] } From 0e585b9a52c499f76068cfd1cd85b1a6eedcc02e Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Wed, 24 Apr 2024 10:21:05 +0200 Subject: [PATCH 003/658] Update to Ruby 3.2.4 (#30036) --- .ruby-version | 2 +- Dockerfile | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.ruby-version b/.ruby-version index b347b11eac..351227fca3 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.3 +3.2.4 diff --git a/Dockerfile b/Dockerfile index 43bc24295d..a95d41a65b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,15 +7,15 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} -# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.3"] -ARG RUBY_VERSION="3.2.3" +# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.4"] +ARG RUBY_VERSION="3.2.4" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] ARG NODE_MAJOR_VERSION="20" # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] ARG DEBIAN_VERSION="bookworm" # Node image to use for base image based on combined variables (ex: 20-bookworm-slim) FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node -# Ruby image to use for base image based on combined variables (ex: 3.2.3-slim-bookworm) +# Ruby image to use for base image based on combined variables (ex: 3.2.4-slim-bookworm) FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA @@ -29,7 +29,7 @@ ARG MASTODON_VERSION_METADATA="" # See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files ARG RAILS_SERVE_STATIC_FILES="true" # Allow to use YJIT compiler -# See: https://github.com/ruby/ruby/blob/v3_2_3/doc/yjit/yjit.md +# See: https://github.com/ruby/ruby/blob/v3_2_4/doc/yjit/yjit.md ARG RUBY_YJIT_ENABLE="1" # Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin] ARG TZ="Etc/UTC" @@ -262,4 +262,4 @@ USER mastodon # Expose default Puma ports EXPOSE 3000 # Set container tini as default entry point -ENTRYPOINT ["/usr/bin/tini", "--"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/tini", "--"] From b903e6909e8d534330d19d5ecefcc1296a92ec36 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 24 Apr 2024 04:32:18 -0400 Subject: [PATCH 004/658] Disable `Style/HashAsLastArrayItem` cop (#30041) --- .rubocop.yml | 5 +++++ .rubocop_todo.yml | 13 ------------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 1b5ce67ee7..542e90b5e3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -182,6 +182,11 @@ Style/FormatStringToken: AllowedMethods: - redirect_with_vary +# Reason: Prevailing style choice +# https://docs.rubocop.org/rubocop/cops_style.html#stylehashaslastarrayitem +Style/HashAsLastArrayItem: + Enabled: false + # Reason: Enforce modern Ruby style # https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax Style/HashSyntax: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 3f2e9aee62..c2826d718c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -128,19 +128,6 @@ Style/GuardClause: - 'lib/mastodon/cli/media.rb' - 'lib/tasks/repo.rake' -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: braces, no_braces -Style/HashAsLastArrayItem: - Exclude: - - 'app/controllers/admin/statuses_controller.rb' - - 'app/controllers/api/v1/statuses_controller.rb' - - 'app/models/concerns/account/counters.rb' - - 'app/models/concerns/status/threading_concern.rb' - - 'app/models/status.rb' - - 'app/services/batched_remove_status_service.rb' - - 'app/services/notify_service.rb' - # This cop supports unsafe autocorrection (--autocorrect-all). Style/HashTransformValues: Exclude: From 74012831f61a36b7f52540c5ccafa0f9692a6596 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 24 Apr 2024 10:45:12 +0200 Subject: [PATCH 005/658] Change mute options to be in dropdown on muted users list in web UI (#30049) --- .../mastodon/components/account.jsx | 274 +++++++++--------- .../styles/mastodon/components.scss | 14 +- 2 files changed, 151 insertions(+), 137 deletions(-) diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx index 4a99dd0bbf..3282696d34 100644 --- a/app/javascript/mastodon/components/account.jsx +++ b/app/javascript/mastodon/components/account.jsx @@ -1,17 +1,19 @@ import PropTypes from 'prop-types'; +import { useCallback } from 'react'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import classNames from 'classnames'; import { Link } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import { EmptyAccount } from 'mastodon/components/empty_account'; import { ShortNumber } from 'mastodon/components/short_number'; import { VerifiedBadge } from 'mastodon/components/verified_badge'; +import DropdownMenuContainer from '../containers/dropdown_menu_container'; import { me } from '../initial_state'; import { Avatar } from './avatar'; @@ -30,151 +32,151 @@ const messages = defineMessages({ unmute_notifications: { id: 'account.unmute_notifications_short', defaultMessage: 'Unmute notifications' }, mute: { id: 'account.mute_short', defaultMessage: 'Mute' }, block: { id: 'account.block_short', defaultMessage: 'Block' }, + more: { id: 'status.more', defaultMessage: 'More' }, }); -class Account extends ImmutablePureComponent { +const Account = ({ size = 46, account, onFollow, onBlock, onMute, onMuteNotifications, hidden, minimal, defaultAction, withBio }) => { + const intl = useIntl(); - static propTypes = { - size: PropTypes.number, - account: ImmutablePropTypes.record, - onFollow: PropTypes.func, - onBlock: PropTypes.func, - onMute: PropTypes.func, - onMuteNotifications: PropTypes.func, - intl: PropTypes.object.isRequired, - hidden: PropTypes.bool, - minimal: PropTypes.bool, - defaultAction: PropTypes.string, - withBio: PropTypes.bool, - }; + const handleFollow = useCallback(() => { + onFollow(account); + }, [onFollow, account]); - static defaultProps = { - size: 46, - }; + const handleBlock = useCallback(() => { + onBlock(account); + }, [onBlock, account]); - handleFollow = () => { - this.props.onFollow(this.props.account); - }; + const handleMute = useCallback(() => { + onMute(account); + }, [onMute, account]); - handleBlock = () => { - this.props.onBlock(this.props.account); - }; + const handleMuteNotifications = useCallback(() => { + onMuteNotifications(account, true); + }, [onMuteNotifications, account]); - handleMute = () => { - this.props.onMute(this.props.account); - }; + const handleUnmuteNotifications = useCallback(() => { + onMuteNotifications(account, false); + }, [onMuteNotifications, account]); - handleMuteNotifications = () => { - this.props.onMuteNotifications(this.props.account, true); - }; - - handleUnmuteNotifications = () => { - this.props.onMuteNotifications(this.props.account, false); - }; - - render () { - const { account, intl, hidden, withBio, defaultAction, size, minimal } = this.props; - - if (!account) { - return ; - } - - if (hidden) { - return ( - <> - {account.get('display_name')} - {account.get('username')} - - ); - } - - let buttons; - - if (account.get('id') !== me && account.get('relationship', null) !== null) { - const following = account.getIn(['relationship', 'following']); - const requested = account.getIn(['relationship', 'requested']); - const blocking = account.getIn(['relationship', 'blocking']); - const muting = account.getIn(['relationship', 'muting']); - - if (requested) { - buttons = .", + "domain_pill.your_handle": "Nama pengguna anda:", "embed.instructions": "Sematkan kiriman ini di situs web Anda dengan menyalin kode di bawah ini.", "embed.preview": "Tampilan akan seperti ini nantinya:", "emoji_button.activity": "Aktivitas", @@ -260,6 +295,10 @@ "follow_request.authorize": "Izinkan", "follow_request.reject": "Tolak", "follow_requests.unlocked_explanation": "Meskipun akun Anda tidak dikunci, staf {domain} menyarankan Anda untuk meninjau permintaan mengikuti dari akun-akun ini secara manual.", + "follow_suggestions.curated_suggestion": "Pilihan staf", + "follow_suggestions.dismiss": "Jangan tampilkan lagi", + "follow_suggestions.hints.featured": "Profil ini telah dipilih sendiri oleh tim {domain}.", + "follow_suggestions.hints.friends_of_friends": "Profil ini populer di kalangan orang yang anda ikuti.", "followed_tags": "Tagar yang diikuti", "footer.about": "Tentang", "footer.directory": "Direktori profil", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 0b328c7386..3ca9a8d11e 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -297,6 +297,7 @@ "filter_modal.select_filter.subtitle": "使用既有類別,或創建一個新類別", "filter_modal.select_filter.title": "過濾此帖文", "filter_modal.title.status": "過濾一則帖文", + "filtered_notifications_banner.mentions": "{count, plural, one {則提及} other {則提及}}", "filtered_notifications_banner.pending_requests": "來自 {count, plural, =0 {0 位} other {# 位}}你可能認識的人的通知", "filtered_notifications_banner.title": "已過濾之通知", "firehose.all": "全部", diff --git a/config/locales/devise.eo.yml b/config/locales/devise.eo.yml index af1769aa66..193fecc757 100644 --- a/config/locales/devise.eo.yml +++ b/config/locales/devise.eo.yml @@ -12,6 +12,7 @@ eo: last_attempt: Vi ankoraŭ povas provi unufoje antaŭ ol via konto estos ŝlosita. locked: Via konto estas ŝlosita. not_found_in_database: Nevalida %{authentication_keys} aŭ pasvorto. + omniauth_user_creation_failure: Eraro okazis kreinte konton por ĉi tiu identeco. pending: Via konto ankoraŭ estas kontrolata. timeout: Via seanco eksvalidiĝis. Bonvolu ensaluti denove por daŭrigi. unauthenticated: Vi devas ensaluti aŭ registriĝi antaŭ ol daŭrigi. @@ -39,7 +40,7 @@ eo: explanation: Retajpu la novan adreson por ŝanĝi vian retpoŝtadreson. extra: Se ĉi tiu ŝanĝo ne estis komencita de vi, bonvolu ignori ĉi tiun retmesaĝon. La retadreso por la Mastodon-konto ne ŝanĝiĝos se vi ne aliras la supran ligilon. subject: 'Mastodon: Konfirmi retpoŝton por %{instance}' - title: Kontrolu retpoŝtadreson + title: Kontroli retpoŝtadreson reset_password_instructions: action: Ŝanĝi pasvorton explanation: Vi petis novan pasvorton por via konto. diff --git a/config/locales/doorkeeper.bg.yml b/config/locales/doorkeeper.bg.yml index 8e026794ee..7633156d78 100644 --- a/config/locales/doorkeeper.bg.yml +++ b/config/locales/doorkeeper.bg.yml @@ -174,6 +174,7 @@ bg: read:filters: преглед на вашите филтри read:follows: преглед на вашите последвания read:lists: преглед на вашите списъци + read:me: четене само на основните сведения за акаунта ви read:mutes: преглед на вашите заглушавания read:notifications: преглед на вашите известия read:reports: преглед на вашите докладвания diff --git a/config/locales/doorkeeper.ca.yml b/config/locales/doorkeeper.ca.yml index 9706f3db70..80827a87da 100644 --- a/config/locales/doorkeeper.ca.yml +++ b/config/locales/doorkeeper.ca.yml @@ -174,6 +174,7 @@ ca: read:filters: mira els teus filtres read:follows: mira els teus seguiments read:lists: mira les teves llistes + read:me: llegir només la informació bàsica del vostre compte read:mutes: mira els teus silenciats read:notifications: mira les teves notificacions read:reports: mira els teus informes diff --git a/config/locales/doorkeeper.da.yml b/config/locales/doorkeeper.da.yml index 2c8b0d13e1..ed10e14e24 100644 --- a/config/locales/doorkeeper.da.yml +++ b/config/locales/doorkeeper.da.yml @@ -174,6 +174,7 @@ da: read:filters: se dine filtre read:follows: se dine følger read:lists: se dine lister + read:me: læs kun kontoens basisoplysninger read:mutes: se dine tavsgørelser read:notifications: se dine notifikationer read:reports: se dine anmeldelser diff --git a/config/locales/doorkeeper.de.yml b/config/locales/doorkeeper.de.yml index 552dfeba37..80d612255b 100644 --- a/config/locales/doorkeeper.de.yml +++ b/config/locales/doorkeeper.de.yml @@ -174,6 +174,7 @@ de: read:filters: deine Filter einsehen read:follows: sehen, wem du folgst read:lists: deine Listen sehen + read:me: nur deine grundlegenden Kontoinformationen lesen read:mutes: deine Stummschaltungen einsehen read:notifications: deine Benachrichtigungen sehen read:reports: deine Meldungen sehen diff --git a/config/locales/doorkeeper.es-AR.yml b/config/locales/doorkeeper.es-AR.yml index 532db1f30d..47cfc451aa 100644 --- a/config/locales/doorkeeper.es-AR.yml +++ b/config/locales/doorkeeper.es-AR.yml @@ -174,6 +174,7 @@ es-AR: read:filters: ver tus filtros read:follows: ver qué cuentas seguís read:lists: ver tus listas + read:me: leer solo la información básica de tu cuenta read:mutes: ver qué cuentas silenciaste read:notifications: ver tus notificaciones read:reports: ver tus denuncias diff --git a/config/locales/doorkeeper.eu.yml b/config/locales/doorkeeper.eu.yml index e7963672fa..88a63f698b 100644 --- a/config/locales/doorkeeper.eu.yml +++ b/config/locales/doorkeeper.eu.yml @@ -174,6 +174,7 @@ eu: read:filters: ikusi zure iragazkiak read:follows: ikusi zuk jarraitutakoak read:lists: ikusi zure zerrendak + read:me: irakurri soilik zure kontuaren oinarrizko informazioa read:mutes: ikusi zuk mutututakoak read:notifications: ikusi zure jakinarazpenak read:reports: ikusi zure salaketak diff --git a/config/locales/doorkeeper.fi.yml b/config/locales/doorkeeper.fi.yml index fea01d1076..ae8963c76f 100644 --- a/config/locales/doorkeeper.fi.yml +++ b/config/locales/doorkeeper.fi.yml @@ -174,6 +174,7 @@ fi: read:filters: katso suodattimiasi read:follows: katso seurattujasi read:lists: katso listojasi + read:me: lue tilisi perustietoja read:mutes: katso mykistyksiäsi read:notifications: katso ilmoituksiasi read:reports: katso raporttejasi diff --git a/config/locales/doorkeeper.fo.yml b/config/locales/doorkeeper.fo.yml index 78f8701ae9..4f5cc5a645 100644 --- a/config/locales/doorkeeper.fo.yml +++ b/config/locales/doorkeeper.fo.yml @@ -174,6 +174,7 @@ fo: read:filters: síggja tíni filtur read:follows: síggja hvørji tú fylgir read:lists: síggja tínar listar + read:me: les bara grundleggjandi upplýsingar av tínari kontu read:mutes: síggja tínar doyvingar read:notifications: síggja tínar fráboðanir read:reports: síggja tínar meldingar diff --git a/config/locales/doorkeeper.gl.yml b/config/locales/doorkeeper.gl.yml index aa0eae2844..d34c58decc 100644 --- a/config/locales/doorkeeper.gl.yml +++ b/config/locales/doorkeeper.gl.yml @@ -174,6 +174,7 @@ gl: read:filters: ver os filtros read:follows: ver a quen segues read:lists: ver as tuas listaxes + read:me: ler só a información básica da túa conta read:mutes: ver a quen tes acalado read:notifications: ver as notificacións read:reports: ver as túas denuncias diff --git a/config/locales/doorkeeper.he.yml b/config/locales/doorkeeper.he.yml index 9030e45e0c..a6376fa4c1 100644 --- a/config/locales/doorkeeper.he.yml +++ b/config/locales/doorkeeper.he.yml @@ -174,6 +174,7 @@ he: read:filters: צפייה במסננים read:follows: צפייה בנעקבים read:lists: צפיה ברשימותיך + read:me: לקריאה בלבד של פרטי חשבונך הבסיסיים read:mutes: צפיה במושתקיך read:notifications: צפיה בהתראותיך read:reports: צפיה בדוחותיך diff --git a/config/locales/doorkeeper.hu.yml b/config/locales/doorkeeper.hu.yml index 3822e9c202..28ce283ffa 100644 --- a/config/locales/doorkeeper.hu.yml +++ b/config/locales/doorkeeper.hu.yml @@ -174,6 +174,7 @@ hu: read:filters: szűrök megtekintése read:follows: követések megtekintése read:lists: listák megtekintése + read:me: csak a fiókod alapvető adatainak elolvasása read:mutes: némítások megtekintése read:notifications: értesítések megtekintése read:reports: bejelentések megtekintése diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index b41531a1b1..fd7d7a0836 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -87,6 +87,7 @@ ia: read:filters: vider tu filtros read:follows: vider tu sequites read:lists: vider tu listas + read:me: leger solmente le information basic de tu conto read:notifications: vider tu notificationes read:reports: vider tu reportos read:statuses: vider tote le messages diff --git a/config/locales/doorkeeper.is.yml b/config/locales/doorkeeper.is.yml index c1e2d4cfc3..995d507f5b 100644 --- a/config/locales/doorkeeper.is.yml +++ b/config/locales/doorkeeper.is.yml @@ -174,6 +174,7 @@ is: read:filters: skoða síurnar þínar read:follows: sjá hverjum þú fylgist með read:lists: skoða listana þína + read:me: lesa einungis grunnupplýsingar aðgangsins þíns read:mutes: skoða hverja þú þaggar read:notifications: sjá tilkynningarnar þínar read:reports: skoða skýrslurnar þína diff --git a/config/locales/doorkeeper.it.yml b/config/locales/doorkeeper.it.yml index 3fd998fc4a..f39f784665 100644 --- a/config/locales/doorkeeper.it.yml +++ b/config/locales/doorkeeper.it.yml @@ -174,6 +174,7 @@ it: read:filters: visualizzare i tuoi filtri read:follows: visualizzare i tuoi seguiti read:lists: visualizzare i tuoi elenchi + read:me: leggi solo le informazioni di base del tuo account read:mutes: visualizzare i tuoi silenziamenti read:notifications: visualizzare le tue notifiche read:reports: visualizzare le tue segnalazioni diff --git a/config/locales/doorkeeper.ko.yml b/config/locales/doorkeeper.ko.yml index 4721e3acdb..12674cc125 100644 --- a/config/locales/doorkeeper.ko.yml +++ b/config/locales/doorkeeper.ko.yml @@ -174,6 +174,7 @@ ko: read:filters: 필터 보기 read:follows: 팔로우 보기 read:lists: 리스트 보기 + read:me: 내 계정의 기본 정보만을 읽습니다 read:mutes: 뮤트 보기 read:notifications: 알림 보기 read:reports: 신고 보기 diff --git a/config/locales/doorkeeper.nl.yml b/config/locales/doorkeeper.nl.yml index b3e6e79a1a..9554c0ee6f 100644 --- a/config/locales/doorkeeper.nl.yml +++ b/config/locales/doorkeeper.nl.yml @@ -174,6 +174,7 @@ nl: read:filters: jouw filters bekijken read:follows: de accounts die jij volgt bekijken read:lists: jouw lijsten bekijken + read:me: alleen de basisgegevens van jouw account lezen read:mutes: jouw genegeerde gebruikers bekijken read:notifications: jouw meldingen bekijken read:reports: jouw gerapporteerde berichten bekijken diff --git a/config/locales/doorkeeper.nn.yml b/config/locales/doorkeeper.nn.yml index 0e5d1ca455..ab0380c6fa 100644 --- a/config/locales/doorkeeper.nn.yml +++ b/config/locales/doorkeeper.nn.yml @@ -174,6 +174,7 @@ nn: read:filters: sjå filtera dine read:follows: sjå fylgjarane dine read:lists: sjå listene dine + read:me: les berre kontoen din sin grunnleggjande informasjon read:mutes: sjå kven du har målbunde read:notifications: sjå varsla dine read:reports: sjå rapportane dine diff --git a/config/locales/doorkeeper.pl.yml b/config/locales/doorkeeper.pl.yml index 226c0d403c..eefca2de65 100644 --- a/config/locales/doorkeeper.pl.yml +++ b/config/locales/doorkeeper.pl.yml @@ -174,6 +174,7 @@ pl: read:filters: dostęp do filtrów read:follows: dostęp do listy obserwowanych read:lists: dostęp do Twoich list + read:me: odczytaj tylko podstawowe informacje o koncie read:mutes: dostęp do listy wyciszonych read:notifications: możliwość odczytu powiadomień read:reports: dostęp do Twoich zgłoszeń diff --git a/config/locales/doorkeeper.sl.yml b/config/locales/doorkeeper.sl.yml index a613308b28..55e00ff96d 100644 --- a/config/locales/doorkeeper.sl.yml +++ b/config/locales/doorkeeper.sl.yml @@ -174,6 +174,7 @@ sl: read:filters: oglejte si svoje filtre read:follows: oglejte si svoje sledilce read:lists: oglejte si svoje sezname + read:me: preberi le osnovne podatke računa read:mutes: oglejte si svoje utišane read:notifications: oglejte si svoja obvestila read:reports: oglejte si svoje prijave diff --git a/config/locales/doorkeeper.tr.yml b/config/locales/doorkeeper.tr.yml index 47a15e1b8a..f5ebbc5fd8 100644 --- a/config/locales/doorkeeper.tr.yml +++ b/config/locales/doorkeeper.tr.yml @@ -174,6 +174,7 @@ tr: read:filters: süzgeçlerinizi görün read:follows: takip ettiklerinizi görün read:lists: listelerinizi görün + read:me: hesabınızın sadece temel bilgilerini okuma read:mutes: sessize aldıklarınızı görün read:notifications: bildirimlerinizi görün read:reports: raporlarınızı görün diff --git a/config/locales/doorkeeper.uk.yml b/config/locales/doorkeeper.uk.yml index 8af404a736..ac7fbbe15d 100644 --- a/config/locales/doorkeeper.uk.yml +++ b/config/locales/doorkeeper.uk.yml @@ -180,6 +180,7 @@ uk: read:filters: бачити Ваші фільтри read:follows: бачити Ваші підписки read:lists: бачити Ваші списки + read:me: читайте лише основну інформацію вашого облікового запису read:mutes: бачити ваші нехтування read:notifications: бачити Ваші сповіщення read:reports: бачити Ваші скарги diff --git a/config/locales/doorkeeper.vi.yml b/config/locales/doorkeeper.vi.yml index 8375795273..84684d24ca 100644 --- a/config/locales/doorkeeper.vi.yml +++ b/config/locales/doorkeeper.vi.yml @@ -174,6 +174,7 @@ vi: read:filters: xem bộ lọc read:follows: xem những người theo dõi read:lists: xem danh sách + read:me: chỉ đọc thông tin cơ bản tài khoản read:mutes: xem những người đã ẩn read:notifications: xem thông báo read:reports: xem báo cáo của bạn diff --git a/config/locales/doorkeeper.zh-CN.yml b/config/locales/doorkeeper.zh-CN.yml index 36c7fb8127..73f1f9725c 100644 --- a/config/locales/doorkeeper.zh-CN.yml +++ b/config/locales/doorkeeper.zh-CN.yml @@ -174,6 +174,7 @@ zh-CN: read:filters: 查看你的过滤器 read:follows: 查看你的关注 read:lists: 查看你的列表 + read:me: 只读取你账户的基本信息 read:mutes: 查看你的隐藏列表 read:notifications: 查看你的通知 read:reports: 查看你的举报 diff --git a/config/locales/doorkeeper.zh-HK.yml b/config/locales/doorkeeper.zh-HK.yml index 79629b12fe..76d13a74a5 100644 --- a/config/locales/doorkeeper.zh-HK.yml +++ b/config/locales/doorkeeper.zh-HK.yml @@ -174,6 +174,7 @@ zh-HK: read:filters: 檢視你的過濾條件 read:follows: 檢視你關注的人 read:lists: 檢視你的清單 + read:me: 僅讀取帳號的基本資訊 read:mutes: 檢視被你靜音的人 read:notifications: 檢視你的通知 read:reports: 檢視你的檢舉 diff --git a/config/locales/doorkeeper.zh-TW.yml b/config/locales/doorkeeper.zh-TW.yml index f2250b79cb..86827a7122 100644 --- a/config/locales/doorkeeper.zh-TW.yml +++ b/config/locales/doorkeeper.zh-TW.yml @@ -174,6 +174,7 @@ zh-TW: read:filters: 檢視您的過濾條件 read:follows: 檢視您跟隨之使用者 read:lists: 檢視您的列表 + read:me: 僅讀取您的帳號基本資訊 read:mutes: 檢視您靜音的人 read:notifications: 檢視您的通知 read:reports: 檢視您的檢舉 diff --git a/config/locales/eo.yml b/config/locales/eo.yml index d59eadd528..749f80687d 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -74,7 +74,7 @@ eo: follows: Sekvatoj header: Kapa bildo inbox_url: Enira URL - invite_request_text: 가입하려는 이유 + invite_request_text: Kialoj por aliĝi invited_by: Invitita de ip: IP joined: Aliĝis @@ -104,7 +104,7 @@ eo: no_role_assigned: Sen rolo not_subscribed: Ne abonita pending: Pritraktata recenzo - perform_full_suspension: Suspendi + perform_full_suspension: Haltigi previous_strikes: Antaǔaj admonoj previous_strikes_description_html: one: Ĉi tiu konto havas unu admonon. @@ -121,7 +121,7 @@ eo: remote_suspension_reversible_hint_html: La konto estas suspendita, kaj la datumoj estos komplete forigitaj je %{date}. Ĝis tiam, la konto povas esti malsuspendita sen flankefiko. Se vi deziras tuj forigi ĉiujn datumojn de la konto, vi povas fari tion sube. remove_avatar: Forigi la profilbildon remove_header: Forigi kapan bildon - removed_avatar_msg: La rolfiguro de %{username} estas sukcese forigita + removed_avatar_msg: La profilbildo de %{username} estas sukcese forigita removed_header_msg: Kapbildo de %{username} suksece forigita resend_confirmation: already_confirmed: Ĉi tiu uzanto jam estas konfirmita @@ -184,7 +184,7 @@ eo: create_domain_block: Krei Blokadon De Domajno create_email_domain_block: Krei Blokadon De Retpoŝta Domajno create_ip_block: Krei IP-regulon - create_unavailable_domain: Krei nehaveblan domajnon + create_unavailable_domain: Krei Nehaveblan Domajnon create_user_role: Krei Rolon demote_user: Malpromocii Uzanton destroy_announcement: Forigi Anoncon @@ -193,9 +193,9 @@ eo: destroy_domain_allow: Forigi Domajnan Permeson destroy_domain_block: Forigi blokadon de domajno destroy_email_domain_block: Forigi blokadon de retpoŝta domajno - destroy_instance: Forigi domajnon + destroy_instance: Forigi Domajnon destroy_ip_block: Forigi IP-regulon - destroy_status: Forigi mesaĝon + destroy_status: Forigi Afiŝon destroy_unavailable_domain: Forigi Nehaveblan Domajnon destroy_user_role: Detrui Rolon disable_2fa_user: Malebligi 2FA @@ -285,7 +285,7 @@ eo: update_custom_emoji_html: "%{name} ĝisdatigis la emoĝion %{target}" update_domain_block_html: "%{name} ĝisdatigis domajnblokon por %{target}" update_ip_block_html: "%{name} ŝanĝis regulon por IP %{target}" - update_status_html: "%{name} ĝisdatigis mesaĝon de %{target}" + update_status_html: "%{name} ĝisdatigis afiŝon de %{target}" update_user_role_html: "%{name} ŝanĝis la rolon %{target}" deleted_account: forigita konto empty: Neniu ĵurnalo trovita. @@ -567,7 +567,7 @@ eo: disable: Malebligi disabled: Malebligita enable: Ebligi - enable_hint: Post ebligo, via servilo abonos ĉiujn publikajn mesaĝojn de tiu ripetilo, kaj komencos sendi publikajn mesaĝojn de la servilo al ĝi. + enable_hint: Post ebligo, via servilo abonos ĉiujn publikajn mesaĝojn de tiu ripetilo, kaj komencos sendi publikajn afiŝojn de la servilo al ĝi. enabled: Ebligita inbox_url: URL de la ripetilo pending: Atendante aprobon de la ripetilo @@ -587,7 +587,7 @@ eo: action_log: Ĵurnalo de revizo action_taken_by: Ago farita de actions: - delete_description_html: Raportitaj mesaĝoj forigotas kaj admono rekorditas. + delete_description_html: Raportitaj afiŝoj estos forigita kaj admono estos rekordita por helpi vin indiki estontajn afiŝojn de la sama konto kontraŭ reguloj. mark_as_sensitive_description_html: La audovidaĵo en la raportita mesaĝo markotas kiel sentema kaj admono rekorditas. other_description_html: Vidu pli da ebloj por regi la sintenon de la konto kaj por personigi la komunikadon kun la raportita konto. resolve_description_html: Nenio okazotas al la raportita konto kaj la raporto fermotas. @@ -634,7 +634,7 @@ eo: resolved: Solvitaj resolved_msg: Signalo sukcese solvita! skip_to_actions: Salti al agoj - status: Mesaĝoj + status: Afiŝo statuses: Raportita enhavo statuses_description_html: Sentema enhavo referencitas kun la raportita konto summary: @@ -787,6 +787,7 @@ eo: types: major: Ĉefa eldono minor: Neĉefa eldono + version: Versio statuses: account: Skribanto application: Aplikaĵo @@ -803,12 +804,12 @@ eo: media: title: Aŭdovidaĵoj metadata: Metadatumoj - no_status_selected: Neniu mesaĝo estis ŝanĝita ĉar neniu estis elektita + no_status_selected: Neniu afiŝo estis ŝanĝita ĉar neniu estis elektita open: Malfermi afiŝojn original_status: Originala afiŝo reblogs: Reblogaĵoj status_changed: Afiŝo ŝanĝiĝis - title: Mesaĝoj de la konto + title: Afiŝoj de la konto trending: Popularaĵoj visibility: Videbleco with_media: Kun aŭdovidaĵoj @@ -816,7 +817,7 @@ eo: actions: delete_statuses: "%{name} forigis afiŝojn de %{target}" disable: "%{name} frostigis la konton de %{target}" - mark_statuses_as_sensitive: "%{name} markis mesaĝojn de %{target} kiel sentemaj" + mark_statuses_as_sensitive: "%{name} markis afiŝojn de %{target} kiel tiklan" none: "%{name} sendis averton al %{target}" sensitive: "%{name} markis konton de %{target} kiel sentema" silence: "%{name} limigis la konton de %{target}" @@ -827,6 +828,8 @@ eo: system_checks: database_schema_check: message_html: Estas pritraktataj datumbazaj migradoj. Bonvolu ekzekuti ilin por certigi, ke la apliko kondutas kiel atendite + elasticsearch_preset: + action: Legi dokumentaron elasticsearch_running_check: message_html: Ne eblas konekti Elasticsearch. Bonvolu kontroli ke ĝi funkcias, aǔ malŝaltu plentekstan serĉon elasticsearch_version_check: @@ -940,7 +943,7 @@ eo: admin_mailer: new_appeal: actions: - delete_statuses: por forigi iliajn mesaĝojn + delete_statuses: por forigi iliajn afiŝojn disable: por frostigi ties konton mark_statuses_as_sensitive: por marki iliajn mesaĝojn kiel sentemaj none: averto @@ -991,7 +994,7 @@ eo: unsubscribe: Malabonu view: 'Vidi:' view_profile: Vidi profilon - view_status: Vidi mesaĝon + view_status: Vidi afiŝon applications: created: Aplikaĵo sukcese kreita destroyed: Aplikaĵo sukcese forigita @@ -1131,7 +1134,7 @@ eo: recipient: Senditas por reject_appeal: Malakcepti apelacion status: 'Afiŝo #%{id}' - status_removed: Mesaĝo jam forigitas de sistemo + status_removed: Afiŝo jam estas forigita de sistemo title: "%{action} de %{date}" title_actions: delete_statuses: Forigo de afiŝo @@ -1199,8 +1202,8 @@ eo: edit: add_keyword: Aldoni ĉefvorton keywords: Ĉefvortoj - statuses: Individuaj mesaĝoj - statuses_hint_html: Ĉi tiu filtrilo kongruas kelkajn mesaĝojn. Kontrolu mesaĝojn de la filtrilo. + statuses: Individuaj afiŝoj + statuses_hint_html: Ĉi tiu filtrilo kongruas kelkajn afiŝojn. Kontroli afiŝojn de la filtrilo. title: Ŝanĝi filtrilojn errors: deprecated_api_multiple_keywords: Ĉi tiuj parametroj ne povas ŝanĝitis de ĉi tiu programaro. Uzu pli novan programaron. @@ -1218,8 +1221,8 @@ eo: one: "%{count} afiŝo" other: "%{count} afiŝoj" statuses_long: - one: "%{count} mesaĝo kaŝita" - other: "%{count} mesaĝoj kaŝita" + one: "%{count} afiŝo estas kaŝita" + other: "%{count} afiŝoj estas kaŝitaj" title: Filtriloj new: save: Konservi novan filtrilon @@ -1230,7 +1233,7 @@ eo: remove: Forigi de filtrilo index: hint: Ĉi tiu filtrilo kongruas kelkaj mesaĝoj sendepende de aliaj kriterioj. - title: Filtritaj mesaĝoj + title: Filtritaj afiŝoj generic: all: Ĉio all_items_on_page_selected_html: @@ -1644,16 +1647,16 @@ eo: interaction_exceptions_explanation: Sciu ke estas neniu garantio ke mesaĝo estos forigita se ĝi iras sub la limo de diskonigoj aŭ stelumoj post atingi ĝin. keep_direct: Konservi rektajn mesaĝojn keep_direct_hint: Ne forigos viajn rektajn mesagôjn - keep_media: Konservi mesaĝojn kun aŭdovidaj aldonaĵoj + keep_media: Konservi afiŝojn kun aŭdovidaj aldonaĵoj keep_media_hint: Ne forigi mesaĝojn kiuj enhavas aŭdovidajn aldonaĵojn - keep_pinned: Konservi alpinglitajn mesaĝojn + keep_pinned: Konservi alpinglitajn afiŝojn keep_pinned_hint: Ne forigi viajn ajn alpinglitajn mesaĝojn keep_polls: Konservi enketojn keep_polls_hint: Ne forigi viajn ajn enketojn - keep_self_bookmark: Konservi mesaĝojn kiun vi legsignis + keep_self_bookmark: Konservi afiŝojn kiun vi legsignis keep_self_bookmark_hint: Ne forigi viajn siajn mesaĝojn se vi legsignis ilin - keep_self_fav: Konservi mesaĝojn kiujn vi stelumis - keep_self_fav_hint: Ne forigi proprajn mesaĝojn se vi stelumis ilin + keep_self_fav: Konservi afiŝojn kiujn vi stelumis + keep_self_fav_hint: Ne forigi proprajn afiŝojn se vi stelumis ilin min_age: '1209600': 2 semajnoj '15778476': 6 monatoj @@ -1664,7 +1667,7 @@ eo: '63113904': 2 jaroj '7889238': 3 monatoj min_age_label: Aĝlimo - min_favs: Konservi mesaĝojn stelumitajn almenaŭ + min_favs: Konservi afiŝojn stelumitajn almenaŭ min_favs_hint: Oni ne forigas viajn afiŝojn, kiuj estas diskonigitaj almenaŭ ĉi tiun nombron da fojoj. Lasu malplena por forigi afiŝojn sendepende de iliaj nombroj da diskonigoj min_reblogs: Konservi diskonitajn mesaĝojn almenau min_reblogs_hint: Oni ne forigas viajn afiŝojn kiuj estas diskonigitaj almenaŭ ĉi tiun nombron da fojoj. Lasu malplena por forigi afiŝojn sendepende de iliaj nombroj da diskonigoj @@ -1738,11 +1741,11 @@ eo: silence: Vi ankorau povas uzi vian konton, sed nur personoj kiuj jam sekvas vin vidos viajn mesaĝojn en tiu ĉi servilo, kaj vi eble estos ekskluzive el diversaj malkovrigaj funkcioj. Tamen, aliaj ankoraŭ povas permane eksekvi vin. suspend: Vi ne povas uzi vian konton plu, kaj via profilo kaj aliaj datumoj ne estas disponeblaj plu. reason: 'Kialo:' - statuses: 'Mesaĝoj ripetitaj:' + statuses: 'Afiŝoj citataj:' subject: - delete_statuses: Viaj mesaĝoj ĉe %{acct} forigitas + delete_statuses: Viaj afiŝoj ĉe %{acct} estas forigitaj disable: Via konto %{acct} estas frostigita - mark_statuses_as_sensitive: Viaj mesaĝoj ĉe %{acct} markitas kiel sentemaj + mark_statuses_as_sensitive: Viaj afiŝoj ĉe %{acct} estas markitaj kiel tiklemaj none: Averto por %{acct} sensitive: Viaj mesaĝoj ĉe %{acct} markitas kiel sentemaj malantau ol nun silence: Oni limigis vian konton %{acct} diff --git a/config/locales/ia.yml b/config/locales/ia.yml index a167b5d8cd..6c99293156 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -15,17 +15,27 @@ ia: instance_actor_flash: Iste conto es un agente virtual usate pro representar le servitor mesme e non alcun usator individual. Illo es usate pro le federation e non debe esser suspendite. last_active: ultime activitate link_verified_on: Le proprietate de iste ligamine ha essite verificate le %{date} + nothing_here: Il ha nihil ci! + pin_errors: + following: Tu debe primo sequer le persona que tu vole indorsar posts: one: Message other: Messages posts_tab_heading: Messages admin: + account_actions: + action: Exequer action + title: Exequer action de moderation sur %{acct} account_moderation_notes: create: Lassar un nota created_msg: Nota de moderation create con successo! + destroyed_msg: Nota de moderation destruite con successo! accounts: add_email_domain_block: Blocar dominio de e-mail + approve: Approbar + approved_msg: Demanda de inscription de %{username} approbate con successo are_you_sure: Es tu secur? + avatar: Avatar by_domain: Dominio change_email: changed_msg: Email cambiate con successo! @@ -34,6 +44,11 @@ ia: new_email: Nove e-mail submit: Cambiar e-mail title: Cambiar e-mail pro %{username} + change_role: + changed_msg: Rolo cambiate con successo! + label: Cambiar rolo + no_role: Necun rolo + title: Cambiar rolo pro %{username} confirm: Confirmar confirmed: Confirmate confirming: In confirmation @@ -42,25 +57,59 @@ ia: deleted: Delite demote: Degradar destroyed_msg: Le datos de %{username} ora es in cauda pro su imminente deletion + disable: Gelar + disable_sign_in_token_auth: Disactivar le authentication per token in e-mail disable_two_factor_authentication: Disactivar 2FA + disabled: Gelate display_name: Nomine visibile domain: Dominio edit: Modificar email: E-mail email_status: Stato de e-mail + enable: Disgelar + enable_sign_in_token_auth: Activar le authentication per token in e-mail enabled: Activate + enabled_msg: Conto de %{username} disgelate con successo followers: Sequitores + follows: Sequites + header: Capite + inbox_url: URL de cassa de entrata + invite_request_text: Motivos pro le inscription + invited_by: Invitate per + ip: IP + joined: Inscription location: all: Toto + local: Local + remote: Remote title: Location + login_status: Stato de session + media_attachments: Annexos multimedial + memorialize: Render commemorative + memorialized: Conto commemorative + memorialized_msg: "%{username} ha essite convertite in un conto commemorative" moderation: active: Active all: Toto disabled: Disactivate + pending: In tractamento + silenced: Limitate + suspended: Suspendite + title: Moderation moderation_notes: Notas de moderation most_recent_activity: Activitate plus recente most_recent_ip: IP plus recente + no_account_selected: Necun conto ha essite cambiate perque necun ha essite seligite + no_limits_imposed: Necun limite imponite + no_role_assigned: Necun rolo assignate + not_subscribed: Non subscribite + pending: Attende revision + perform_full_suspension: Suspender + previous_strikes: Previe admonitiones + promote: Promover + protocol: Protocollo public: Public + push_subscription_expires: Subscription PuSH expira le redownload: Actualisar profilo resend_confirmation: already_confirmed: Iste usator jam es confirmate @@ -237,6 +286,9 @@ ia: updated_at: Actualisate view_profile: Vider profilo roles: + assigned_users: + one: "%{count} usator" + other: "%{count} usatores" everyone: Permissiones predefinite privileges: delete_user_data: Deler le datos de usator diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 4c22335eaa..8de8e4887e 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -1671,6 +1671,7 @@ pt-BR: domain_block: Suspensão do servidor (%{target_name}) user_domain_block: Você bloqueou %{target_name} lost_followers: Seguidores perdidos + purged: As informações sobre este servidor foram eliminadas pelos administradores do seu servidor. type: Evento statuses: attached: @@ -1765,6 +1766,7 @@ pt-BR: contrast: Mastodon (Alto contraste) default: Mastodon (Noturno) mastodon-light: Mastodon (Diurno) + system: Automático (usar tema do sistema) time: formats: default: "%H:%M em %d de %b de %Y" diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index 2f04ce982e..7012cdb1cd 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -30,6 +30,7 @@ ia: defaults: autofollow: Invitar a sequer tu conto avatar: Pictura de profilo + chosen_languages: Filtrar linguas confirm_new_password: Confirmar nove contrasigno confirm_password: Confirmar contrasigno current_password: Contrasigno actual @@ -39,6 +40,7 @@ ia: new_password: Nove contrasigno password: Contrasigno setting_advanced_layout: Activar le interfacie web avantiate + setting_always_send_emails: Sempre inviar notificationes per e-mail setting_default_language: Lingua de publication setting_display_media_default: Predefinite setting_display_media_hide_all: Celar toto From f4a53f3fb480bb1b9f0fa0d2849b6dc4300f679b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 24 Apr 2024 04:56:28 -0400 Subject: [PATCH 007/658] Extract constants for column size length validation limits (#30045) --- app/models/account_moderation_note.rb | 4 +++- app/models/account_note.rb | 4 +++- app/models/invite.rb | 4 +++- app/models/report.rb | 4 +++- app/models/report_note.rb | 4 +++- app/models/rule.rb | 4 +++- app/models/user_invite_request.rb | 4 +++- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/app/models/account_moderation_note.rb b/app/models/account_moderation_note.rb index ff399bab0c..ad49b24229 100644 --- a/app/models/account_moderation_note.rb +++ b/app/models/account_moderation_note.rb @@ -13,10 +13,12 @@ # class AccountModerationNote < ApplicationRecord + CONTENT_SIZE_LIMIT = 500 + belongs_to :account belongs_to :target_account, class_name: 'Account' scope :latest, -> { reorder('created_at DESC') } - validates :content, presence: true, length: { maximum: 500 } + validates :content, presence: true, length: { maximum: CONTENT_SIZE_LIMIT } end diff --git a/app/models/account_note.rb b/app/models/account_note.rb index 9bc704d988..317e6873fa 100644 --- a/app/models/account_note.rb +++ b/app/models/account_note.rb @@ -14,9 +14,11 @@ class AccountNote < ApplicationRecord include RelationshipCacheable + COMMENT_SIZE_LIMIT = 2_000 + belongs_to :account belongs_to :target_account, class_name: 'Account' validates :account_id, uniqueness: { scope: :target_account_id } - validates :comment, length: { maximum: 2_000 } + validates :comment, length: { maximum: COMMENT_SIZE_LIMIT } end diff --git a/app/models/invite.rb b/app/models/invite.rb index c0cbc58458..2fe9f22fbe 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -19,12 +19,14 @@ class Invite < ApplicationRecord include Expireable + COMMENT_SIZE_LIMIT = 420 + belongs_to :user, inverse_of: :invites has_many :users, inverse_of: :invite, dependent: nil scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) } - validates :comment, length: { maximum: 420 } + validates :comment, length: { maximum: COMMENT_SIZE_LIMIT } before_validation :set_code diff --git a/app/models/report.rb b/app/models/report.rb index df7e3d2efc..3df5a20e18 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -26,6 +26,8 @@ class Report < ApplicationRecord include Paginable include RateLimitable + COMMENT_SIZE_LIMIT = 1_000 + rate_limit by: :account, family: :reports belongs_to :account @@ -46,7 +48,7 @@ class Report < ApplicationRecord # A report is considered local if the reporter is local delegate :local?, to: :account - validates :comment, length: { maximum: 1_000 }, if: :local? + validates :comment, length: { maximum: COMMENT_SIZE_LIMIT }, if: :local? validates :rule_ids, absence: true, if: -> { (category_changed? || rule_ids_changed?) && !violation? } validate :validate_rule_ids, if: -> { (category_changed? || rule_ids_changed?) && violation? } diff --git a/app/models/report_note.rb b/app/models/report_note.rb index 74b46027e8..b5c40a18b1 100644 --- a/app/models/report_note.rb +++ b/app/models/report_note.rb @@ -13,10 +13,12 @@ # class ReportNote < ApplicationRecord + CONTENT_SIZE_LIMIT = 500 + belongs_to :account belongs_to :report, inverse_of: :notes, touch: true scope :latest, -> { reorder(created_at: :desc) } - validates :content, presence: true, length: { maximum: 500 } + validates :content, presence: true, length: { maximum: CONTENT_SIZE_LIMIT } end diff --git a/app/models/rule.rb b/app/models/rule.rb index f28dc2ffeb..99a36397aa 100644 --- a/app/models/rule.rb +++ b/app/models/rule.rb @@ -15,9 +15,11 @@ class Rule < ApplicationRecord include Discard::Model + TEXT_SIZE_LIMIT = 300 + self.discard_column = :deleted_at - validates :text, presence: true, length: { maximum: 300 } + validates :text, presence: true, length: { maximum: TEXT_SIZE_LIMIT } scope :ordered, -> { kept.order(priority: :asc, id: :asc) } end diff --git a/app/models/user_invite_request.rb b/app/models/user_invite_request.rb index 2b76c88b94..9dd6775166 100644 --- a/app/models/user_invite_request.rb +++ b/app/models/user_invite_request.rb @@ -12,6 +12,8 @@ # class UserInviteRequest < ApplicationRecord + TEXT_SIZE_LIMIT = 420 + belongs_to :user, inverse_of: :invite_request - validates :text, presence: true, length: { maximum: 420 } + validates :text, presence: true, length: { maximum: TEXT_SIZE_LIMIT } end From b12847462597cf590ec3d9c05635cd736024d335 Mon Sep 17 00:00:00 2001 From: Tim Rogers Date: Wed, 24 Apr 2024 04:09:21 -0500 Subject: [PATCH 008/658] Fixed rendering of excess whitespace in status card titles (#30017) --- app/lib/link_details_extractor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/link_details_extractor.rb b/app/lib/link_details_extractor.rb index bb031986d6..bec7d3a455 100644 --- a/app/lib/link_details_extractor.rb +++ b/app/lib/link_details_extractor.rb @@ -156,7 +156,7 @@ class LinkDetailsExtractor end def title - html_entities.decode(structured_data&.headline || opengraph_tag('og:title') || document.xpath('//title').map(&:content).first) + html_entities.decode(structured_data&.headline || opengraph_tag('og:title') || document.xpath('//title').map(&:content).first).strip end def description From d9eee9bf9a3a3e99acb1cea12082faf0fe8de0f9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 24 Apr 2024 10:56:54 -0400 Subject: [PATCH 009/658] Remove column defaults for `status_pins` timestamp columns (#29261) --- ...17171534_remove_defaults_for_status_pins_timestamps.rb | 8 ++++++++ db/schema.rb | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240217171534_remove_defaults_for_status_pins_timestamps.rb diff --git a/db/migrate/20240217171534_remove_defaults_for_status_pins_timestamps.rb b/db/migrate/20240217171534_remove_defaults_for_status_pins_timestamps.rb new file mode 100644 index 0000000000..301371a02d --- /dev/null +++ b/db/migrate/20240217171534_remove_defaults_for_status_pins_timestamps.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class RemoveDefaultsForStatusPinsTimestamps < ActiveRecord::Migration[7.1] + def change + change_column_default :status_pins, :created_at, from: -> { 'CURRENT_TIMESTAMP' }, to: nil + change_column_default :status_pins, :updated_at, from: -> { 'CURRENT_TIMESTAMP' }, to: nil + end +end diff --git a/db/schema.rb b/db/schema.rb index 6a52333a80..a875c6ffc7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1030,8 +1030,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do create_table "status_pins", force: :cascade do |t| t.bigint "account_id", null: false t.bigint "status_id", null: false - t.datetime "created_at", precision: nil, default: -> { "now()" }, null: false - t.datetime "updated_at", precision: nil, default: -> { "now()" }, null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false t.index ["account_id", "status_id"], name: "index_status_pins_on_account_id_and_status_id", unique: true t.index ["status_id"], name: "index_status_pins_on_status_id" end From 85fdbd0ad53837c9209acf3fb45811d5bae41cd9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:50:54 +0200 Subject: [PATCH 010/658] New Crowdin Translations (automated) (#30062) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/de.json | 10 +++++----- app/javascript/mastodon/locales/ig.json | 12 ++++++++++++ app/javascript/mastodon/locales/ja.json | 2 +- app/javascript/mastodon/locales/pt-BR.json | 1 + app/javascript/mastodon/locales/sv.json | 1 + config/locales/de.yml | 2 +- config/locales/devise.de.yml | 2 +- config/locales/doorkeeper.es-MX.yml | 1 + config/locales/doorkeeper.es.yml | 1 + config/locales/doorkeeper.pt-BR.yml | 1 + config/locales/doorkeeper.sv.yml | 1 + config/locales/pt-BR.yml | 2 ++ config/locales/simple_form.pt-BR.yml | 1 + 13 files changed, 29 insertions(+), 8 deletions(-) diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index a1ba25fede..8b52cdb3cc 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -536,11 +536,11 @@ "onboarding.follows.empty": "Bedauerlicherweise können aktuell keine Ergebnisse angezeigt werden. Du kannst die Suche verwenden oder den Reiter „Entdecken“ auswählen, um neue Leute zum Folgen zu finden – oder du versuchst es später erneut.", "onboarding.follows.lead": "Deine Startseite ist der primäre Anlaufpunkt, um Mastodon zu erleben. Je mehr Profilen du folgst, umso aktiver und interessanter wird sie. Damit du direkt loslegen kannst, gibt es hier ein paar Vorschläge:", "onboarding.follows.title": "Personalisiere deine Startseite", - "onboarding.profile.discoverable": "Mein Profil auffindbar machen", + "onboarding.profile.discoverable": "Mein Profil darf entdeckt werden", "onboarding.profile.discoverable_hint": "Wenn du entdeckt werden möchtest, dann können deine Beiträge in Suchergebnissen und Trends erscheinen. Dein Profil kann ebenfalls anderen mit ähnlichen Interessen vorgeschlagen werden.", "onboarding.profile.display_name": "Anzeigename", "onboarding.profile.display_name_hint": "Dein richtiger Name oder dein Fantasiename …", - "onboarding.profile.lead": "Du kannst das später in den Einstellungen vervollständigen, wo noch mehr Anpassungsmöglichkeiten zur Verfügung stehen.", + "onboarding.profile.lead": "Du kannst dein Profil später in den Einstellungen vervollständigen. Dort stehen weitere Anpassungsmöglichkeiten zur Verfügung.", "onboarding.profile.note": "Über mich", "onboarding.profile.note_hint": "Du kannst andere @Profile erwähnen oder #Hashtags verwenden …", "onboarding.profile.save_and_continue": "Speichern und fortfahren", @@ -556,16 +556,16 @@ "onboarding.start.title": "Du hast es geschafft!", "onboarding.steps.follow_people.body": "Interessanten Profilen zu folgen ist das, was Mastodon ausmacht.", "onboarding.steps.follow_people.title": "Personalisiere deine Startseite", - "onboarding.steps.publish_status.body": "Begrüße die Welt mit Text, Fotos, Videos oder Umfragen {emoji}", + "onboarding.steps.publish_status.body": "Begrüße die Welt mit Text, Fotos, Videos oder Umfragen. {emoji}", "onboarding.steps.publish_status.title": "Erstelle deinen ersten Beitrag", "onboarding.steps.setup_profile.body": "Mit einem vollständigen Profil interagieren andere eher mit dir.", "onboarding.steps.setup_profile.title": "Personalisiere dein Profil", - "onboarding.steps.share_profile.body": "Lass deine Freund*innen wissen, wie sie dich auf Mastodon finden können", + "onboarding.steps.share_profile.body": "Lass deine Freund*innen wissen, wie sie dich auf Mastodon finden können.", "onboarding.steps.share_profile.title": "Teile dein Mastodon-Profil", "onboarding.tips.2fa": "Wusstest du schon? Du kannst die Sicherheit deines Kontos erhöhen, indem du die Zwei-Faktor-Authentisierung in deinen Kontoeinstellungen aktivierst. Dafür ist keine Telefonnummer notwendig und es funktioniert jede beliebige TOTP-App!", "onboarding.tips.accounts_from_other_servers": "Wusstest du schon? Da Mastodon dezentralisiert ist, werden einige Profile, denen du begegnest, auf anderen Servern als deinem bereitgestellt. Und trotzdem kannst du uneingeschränkt mit ihnen interagieren! Der Servername befindet sich in der zweiten Hälfte ihres Profilnamens!", "onboarding.tips.migration": "Wusstest du schon? Wenn du das Gefühl hast, dass {domain} in Zukunft nicht die richtige Serverwahl für dich ist, kannst du auf einen anderen Mastodon-Server umziehen, ohne deine Follower zu verlieren. Du kannst sogar deinen eigenen Server betreiben!", - "onboarding.tips.verification": "Wusstest du schon? Du kannst dein Konto verifizieren, indem du auf deiner Website auf dein Mastodon-Profil verlinkst und den Link deiner Website zu deinem Profil hinzufügst. Keine Gebühren oder Dokumente erforderlich!", + "onboarding.tips.verification": "Wusstest du schon? Du kannst dein Konto verifizieren, indem du auf deiner Website auf dein Mastodon-Profil verlinkst und den Link deiner Website zu deinem Profil hinzufügst. Völlig kostenlos und ohne Dokumente einsenden zu müssen!", "password_confirmation.exceeds_maxlength": "Passwortbestätigung überschreitet die maximal erlaubte Zeichenanzahl", "password_confirmation.mismatching": "Passwortbestätigung stimmt nicht überein", "picture_in_picture.restore": "Zurücksetzen", diff --git a/app/javascript/mastodon/locales/ig.json b/app/javascript/mastodon/locales/ig.json index a9b300fa4f..90253743fc 100644 --- a/app/javascript/mastodon/locales/ig.json +++ b/app/javascript/mastodon/locales/ig.json @@ -20,6 +20,7 @@ "column.bookmarks": "Ebenrụtụakā", "column.home": "Be", "column.lists": "Ndepụta", + "column.notifications": "Nziọkwà", "column.pins": "Pinned post", "column_header.pin": "Gbado na profaịlụ gị", "column_subheading.settings": "Mwube", @@ -42,17 +43,28 @@ "confirmations.reply.confirm": "Zaa", "confirmations.unfollow.confirm": "Kwụsị iso", "conversation.delete": "Hichapụ nkata", + "disabled_account_banner.account_settings": "Mwube akaụntụ", "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.", + "domain_pill.username": "Ahaojiaru", "embed.instructions": "Embed this status on your website by copying the code below.", + "emoji_button.activity": "Mmemme", + "emoji_button.label": "Tibanye emoji", "emoji_button.search": "Chọọ...", + "emoji_button.symbols": "Ọdịmara", "empty_column.account_timeline": "No posts found", "empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}", "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", "errors.unexpected_crash.report_issue": "Kpesa nsogbu", + "explore.trending_links": "Akụkọ", + "firehose.all": "Ha niine", + "follow_request.authorize": "Nye ikike", "footer.privacy_policy": "Iwu nzuzu", "getting_started.heading": "Mbido", "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "home.column_settings.show_replies": "Gosi nzaghachị", + "home.hide_announcements": "Zoo ọkwa", + "home.show_announcements": "Gosi ọkwa", "keyboard_shortcuts.back": "to navigate back", "keyboard_shortcuts.blocked": "to open blocked users list", "keyboard_shortcuts.boost": "to boost", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 30c9eb77a9..f20d93753b 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -298,7 +298,7 @@ "filter_modal.select_filter.title": "この投稿をフィルターする", "filter_modal.title.status": "投稿をフィルターする", "filtered_notifications_banner.mentions": "{count, plural, one {メンション} other {メンション}}", - "filtered_notifications_banner.pending_requests": "{count, plural, =0 {アカウント} other {#アカウント}}からの通知がブロックされています", + "filtered_notifications_banner.pending_requests": "{count, plural, =0 {通知がブロックされているアカウントはありません} other {#アカウントからの通知がブロックされています}}", "filtered_notifications_banner.title": "ブロック済みの通知", "firehose.all": "すべて", "firehose.local": "このサーバー", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 1bb73db238..6bda11058f 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -297,6 +297,7 @@ "filter_modal.select_filter.subtitle": "Use uma categoria existente ou crie uma nova", "filter_modal.select_filter.title": "Filtrar esta publicação", "filter_modal.title.status": "Filtrar uma publicação", + "filtered_notifications_banner.mentions": "{count, plural, one {menção} other {menções}}", "filtered_notifications_banner.pending_requests": "Notificações de {count, plural, =0 {no one} one {one person} other {# people}} que você talvez conheça", "filtered_notifications_banner.title": "Notificações filtradas", "firehose.all": "Tudo", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 80c2031128..2b9f0a51b9 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -297,6 +297,7 @@ "filter_modal.select_filter.subtitle": "Använd en befintlig kategori eller skapa en ny", "filter_modal.select_filter.title": "Filtrera detta inlägg", "filter_modal.title.status": "Filtrera ett inlägg", + "filtered_notifications_banner.mentions": "{count, plural, one {mention} other {mentions}}", "filtered_notifications_banner.pending_requests": "Aviseringar från {count, plural, =0 {ingen} one {en person} other {# personer}} du kanske känner", "filtered_notifications_banner.title": "Filtrerade aviseringar", "firehose.all": "Allt", diff --git a/config/locales/de.yml b/config/locales/de.yml index 67aad15873..27073ff9ee 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1046,7 +1046,7 @@ de: apply_for_account: Konto beantragen captcha_confirmation: help_html: Falls du Probleme beim Lösen des CAPTCHA hast, dann kannst uns über %{email} kontaktieren und wir werden versuchen, dir zu helfen. - hint_html: Fast geschafft! Wir müssen uns vergewissern, dass du ein Mensch bist (damit wir Spam verhindern können!). Bitte löse das CAPTCHA und klicke auf „Weiter“. + hint_html: Fast geschafft! Wir müssen uns vergewissern, dass du ein Mensch bist (damit wir Spam verhindern können!). Bitte löse das CAPTCHA und klicke auf „Fortfahren“. title: Sicherheitsüberprüfung confirmations: awaiting_review: Deine E-Mail-Adresse wurde bestätigt und das Team von %{domain} überprüft nun deine Registrierung. Sobald es dein Konto genehmigt, wirst du eine E-Mail erhalten. diff --git a/config/locales/devise.de.yml b/config/locales/devise.de.yml index 73fa1fa60e..032132cf5c 100644 --- a/config/locales/devise.de.yml +++ b/config/locales/devise.de.yml @@ -25,7 +25,7 @@ de: explanation_when_pending: Du hast dich für eine Einladung bei %{host} mit dieser E-Mail-Adresse beworben. Sobald du deine E-Mail-Adresse bestätigt hast, werden wir deine Anfrage überprüfen. Du kannst dich in dieser Zeit nicht anmelden. Wenn deine Anfrage abgelehnt wird, werden deine Daten entfernt – von dir ist keine weitere Handlung notwendig. Wenn du das nicht warst, dann kannst du diese E-Mail ignorieren. extra_html: Bitte beachte auch die Serverregeln und unsere Datenschutzerklärung. subject: 'Mastodon: Anleitung zum Bestätigen deines Kontos auf %{instance}' - title: Verifiziere E-Mail-Adresse + title: Verifiziere deine E-Mail-Adresse email_changed: explanation: 'Die E-Mail-Adresse deines Kontos wird geändert zu:' extra: Wenn du deine E-Mail-Adresse nicht geändert hast, ist es wahrscheinlich, dass sich jemand Zugang zu deinem Konto verschafft hat. Bitte ändere sofort dein Passwort oder kontaktiere die Administrator*innen des Servers, wenn du aus deinem Konto ausgesperrt bist. diff --git a/config/locales/doorkeeper.es-MX.yml b/config/locales/doorkeeper.es-MX.yml index 082d656bc5..e56e0df3ba 100644 --- a/config/locales/doorkeeper.es-MX.yml +++ b/config/locales/doorkeeper.es-MX.yml @@ -174,6 +174,7 @@ es-MX: read:filters: ver tus filtros read:follows: ver a quién sigues read:lists: ver tus listas + read:me: leer solo la información básica de tu cuenta read:mutes: ver a quién has silenciado read:notifications: ver tus notificaciones read:reports: ver tus informes diff --git a/config/locales/doorkeeper.es.yml b/config/locales/doorkeeper.es.yml index 002f813b32..44e165a215 100644 --- a/config/locales/doorkeeper.es.yml +++ b/config/locales/doorkeeper.es.yml @@ -174,6 +174,7 @@ es: read:filters: ver tus filtros read:follows: ver a quién sigues read:lists: ver tus listas + read:me: leer solo la información básica de tu cuenta read:mutes: ver a quién has silenciado read:notifications: ver tus notificaciones read:reports: ver tus informes diff --git a/config/locales/doorkeeper.pt-BR.yml b/config/locales/doorkeeper.pt-BR.yml index d7e9353b59..150b4339e4 100644 --- a/config/locales/doorkeeper.pt-BR.yml +++ b/config/locales/doorkeeper.pt-BR.yml @@ -174,6 +174,7 @@ pt-BR: read:filters: ver seus filtros read:follows: ver quem você segue read:lists: ver suas listas + read:me: ler só as informações básicas da sua conta read:mutes: ver seus silenciados read:notifications: ver suas notificações read:reports: ver suas denúncias diff --git a/config/locales/doorkeeper.sv.yml b/config/locales/doorkeeper.sv.yml index f2c8bd34b8..d336f08c56 100644 --- a/config/locales/doorkeeper.sv.yml +++ b/config/locales/doorkeeper.sv.yml @@ -174,6 +174,7 @@ sv: read:filters: se dina filter read:follows: se vem du följer read:lists: se dina listor + read:me: läs endast den grundläggande informationen för ditt konto read:mutes: se dina tystningar read:notifications: se dina notiser read:reports: se dina rapporter diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 8de8e4887e..9cb9cadee9 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -1671,6 +1671,8 @@ pt-BR: domain_block: Suspensão do servidor (%{target_name}) user_domain_block: Você bloqueou %{target_name} lost_followers: Seguidores perdidos + lost_follows: Seguidores perdidos + preamble: Você poderá perder seguidores e seguidores quando bloquear um domínio ou quando os seus moderadores decidirem suspender um servidor remoto. Quando isso acontecer, você poderá baixar listas de relações desfeitas, a serem inspecionadas e possivelmente importadas para outro servidor. purged: As informações sobre este servidor foram eliminadas pelos administradores do seu servidor. type: Evento statuses: diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml index 676f5e37a3..c3eea9f118 100644 --- a/config/locales/simple_form.pt-BR.yml +++ b/config/locales/simple_form.pt-BR.yml @@ -116,6 +116,7 @@ pt-BR: sign_up_requires_approval: Novas inscrições exigirão sua aprovação severity: Escolha o que acontecerá com as solicitações deste IP rule: + hint: Opcional. Forneça mais detalhes sobre a regra text: Descreva uma regra ou requisito para os usuários neste servidor. Tente mantê-la curta e simples. sessions: otp: 'Digite o código de dois fatores gerado pelo aplicativo no seu celular ou use um dos códigos de recuperação:' From 0ec061aa8f7383330b26b3323d2fafd9ec7663e3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 25 Apr 2024 18:25:33 +0200 Subject: [PATCH 011/658] Change design of people tab on explore in web UI (#30059) --- .../features/explore/components/card.jsx | 88 +++++++++++++++++++ .../mastodon/features/explore/suggestions.jsx | 9 +- app/javascript/mastodon/locales/en.json | 4 + .../styles/mastodon/components.scss | 79 ++++++++++++++++- 4 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 app/javascript/mastodon/features/explore/components/card.jsx diff --git a/app/javascript/mastodon/features/explore/components/card.jsx b/app/javascript/mastodon/features/explore/components/card.jsx new file mode 100644 index 0000000000..316203060a --- /dev/null +++ b/app/javascript/mastodon/features/explore/components/card.jsx @@ -0,0 +1,88 @@ +import PropTypes from 'prop-types'; +import { useCallback } from 'react'; + +import { FormattedMessage, useIntl, defineMessages } from 'react-intl'; + +import { Link } from 'react-router-dom'; + +import { useDispatch, useSelector } from 'react-redux'; + +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import { followAccount, unfollowAccount } from 'mastodon/actions/accounts'; +import { dismissSuggestion } from 'mastodon/actions/suggestions'; +import { Avatar } from 'mastodon/components/avatar'; +import { Button } from 'mastodon/components/button'; +import { DisplayName } from 'mastodon/components/display_name'; +import { IconButton } from 'mastodon/components/icon_button'; +import { domain } from 'mastodon/initial_state'; + +const messages = defineMessages({ + follow: { id: 'account.follow', defaultMessage: 'Follow' }, + unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, + dismiss: { id: 'follow_suggestions.dismiss', defaultMessage: "Don't show again" }, +}); + +export const Card = ({ id, source }) => { + const intl = useIntl(); + const account = useSelector(state => state.getIn(['accounts', id])); + const relationship = useSelector(state => state.getIn(['relationships', id])); + const dispatch = useDispatch(); + const following = relationship?.get('following') ?? relationship?.get('requested'); + + const handleFollow = useCallback(() => { + if (following) { + dispatch(unfollowAccount(id)); + } else { + dispatch(followAccount(id)); + } + }, [id, following, dispatch]); + + const handleDismiss = useCallback(() => { + dispatch(dismissSuggestion(id)); + }, [id, dispatch]); + + let label; + + switch (source) { + case 'friends_of_friends': + label = ; + break; + case 'similar_to_recently_followed': + label = ; + break; + case 'featured': + label = ; + break; + case 'most_followed': + label = ; + break; + case 'most_interactions': + label = ; + break; + } + + return ( +
+
+ {label} +
+ +
+ + +
+
+ + +
+
+
+
+ ); +}; + +Card.propTypes = { + id: PropTypes.string.isRequired, + source: PropTypes.oneOf(['friends_of_friends', 'similar_to_recently_followed', 'featured', 'most_followed', 'most_interactions']), +}; diff --git a/app/javascript/mastodon/features/explore/suggestions.jsx b/app/javascript/mastodon/features/explore/suggestions.jsx index ba33c4d081..101ec0d195 100644 --- a/app/javascript/mastodon/features/explore/suggestions.jsx +++ b/app/javascript/mastodon/features/explore/suggestions.jsx @@ -10,9 +10,10 @@ import { connect } from 'react-redux'; import { fetchSuggestions } from 'mastodon/actions/suggestions'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; -import AccountCard from 'mastodon/features/directory/components/account_card'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; +import { Card } from './components/card'; + const mapStateToProps = state => ({ suggestions: state.getIn(['suggestions', 'items']), isLoading: state.getIn(['suggestions', 'isLoading']), @@ -54,7 +55,11 @@ class Suggestions extends PureComponent { return (
{isLoading ? : suggestions.map(suggestion => ( - + ))}
); diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index fd44b3952b..a1b79881c5 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "follow_suggestions.curated_suggestion": "Staff pick", "follow_suggestions.dismiss": "Don't show again", + "follow_suggestions.featured_longer": "Hand-picked by the {domain} team", + "follow_suggestions.friends_of_friends_longer": "Popular among people you follow", "follow_suggestions.hints.featured": "This profile has been hand-picked by the {domain} team.", "follow_suggestions.hints.friends_of_friends": "This profile is popular among the people you follow.", "follow_suggestions.hints.most_followed": "This profile is one of the most followed on {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "This profile is similar to the profiles you have most recently followed.", "follow_suggestions.personalized_suggestion": "Personalized suggestion", "follow_suggestions.popular_suggestion": "Popular suggestion", + "follow_suggestions.popular_suggestion_longer": "Popular on {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similar to profiles you recently followed", "follow_suggestions.view_all": "View all", "follow_suggestions.who_to_follow": "Who to follow", "followed_tags": "Followed hashtags", diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index b2139169a5..a1864a4562 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2016,7 +2016,10 @@ a .account__avatar { display: flex; align-items: center; gap: 8px; +} +.account__relationship, +.explore__suggestions__card { .icon-button { border: 1px solid var(--background-border-color); border-radius: 4px; @@ -2964,6 +2967,75 @@ $ui-header-logo-wordmark-width: 99px; display: none; } +.explore__suggestions__card { + padding: 12px 16px; + gap: 8px; + display: flex; + flex-direction: column; + border-bottom: 1px solid var(--background-border-color); + + &:last-child { + border-bottom: 0; + } + + &__source { + padding-inline-start: 60px; + font-size: 13px; + line-height: 16px; + color: $dark-text-color; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + + &__body { + display: flex; + gap: 12px; + align-items: center; + + &__main { + flex: 1 1 auto; + display: flex; + flex-direction: column; + gap: 8px; + min-width: 0; + + &__name-button { + display: flex; + align-items: center; + gap: 8px; + + &__name { + display: block; + color: inherit; + text-decoration: none; + flex: 1 1 auto; + min-width: 0; + } + + .button { + min-width: 80px; + } + + .display-name { + font-size: 15px; + line-height: 20px; + color: $secondary-text-color; + + strong { + font-weight: 700; + } + + &__account { + color: $darker-text-color; + display: block; + } + } + } + } + } +} + @media screen and (max-width: $no-gap-breakpoint - 1px) { .columns-area__panels__pane--compositional { display: none; @@ -7293,10 +7365,11 @@ a.status-card { content: ''; position: absolute; bottom: -1px; - left: 0; - width: 100%; + left: 50%; + transform: translateX(-50%); + width: 40px; height: 3px; - border-radius: 4px; + border-radius: 4px 4px 0 0; background: $highlight-text-color; } } From 4ef0b48b951d65920d3a3d9cdfd099967c5e4f6d Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 25 Apr 2024 19:26:05 +0200 Subject: [PATCH 012/658] Add in-app notifications for moderation actions/warnings (#30065) --- .../components/moderation_warning.tsx | 78 +++++++++++++++++++ .../notifications/components/notification.jsx | 25 ++++++ app/javascript/mastodon/locales/en.json | 9 +++ .../mastodon/reducers/notifications.js | 1 + .../styles/mastodon/components.scss | 3 +- app/models/admin/account_action.rb | 9 ++- app/models/admin/status_batch_action.rb | 12 ++- app/models/notification.rb | 6 +- .../rest/account_warning_serializer.rb | 16 ++++ app/serializers/rest/appeal_serializer.rb | 15 ++++ .../rest/notification_serializer.rb | 5 ++ app/services/notify_service.rb | 4 +- spec/models/admin/account_action_spec.rb | 26 +++---- 13 files changed, 188 insertions(+), 21 deletions(-) create mode 100644 app/javascript/mastodon/features/notifications/components/moderation_warning.tsx create mode 100644 app/serializers/rest/account_warning_serializer.rb create mode 100644 app/serializers/rest/appeal_serializer.rb diff --git a/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx b/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx new file mode 100644 index 0000000000..02ae9b371e --- /dev/null +++ b/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx @@ -0,0 +1,78 @@ +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import WarningIcon from '@/material-icons/400-24px/warning-fill.svg?react'; +import { Icon } from 'mastodon/components/icon'; + +// This needs to be kept in sync with app/models/account_warning.rb +const messages = defineMessages({ + none: { + id: 'notification.moderation_warning.action_none', + defaultMessage: 'Your account has received a moderation warning.', + }, + disable: { + id: 'notification.moderation_warning.action_disable', + defaultMessage: 'Your account has been disabled.', + }, + mark_statuses_as_sensitive: { + id: 'notification.moderation_warning.action_mark_statuses_as_sensitive', + defaultMessage: 'Some of your posts have been marked as sensitive.', + }, + delete_statuses: { + id: 'notification.moderation_warning.action_delete_statuses', + defaultMessage: 'Some of your posts have been removed.', + }, + sensitive: { + id: 'notification.moderation_warning.action_sensitive', + defaultMessage: 'Your posts will be marked as sensitive from now on.', + }, + silence: { + id: 'notification.moderation_warning.action_silence', + defaultMessage: 'Your account has been limited.', + }, + suspend: { + id: 'notification.moderation_warning.action_suspend', + defaultMessage: 'Your account has been suspended.', + }, +}); + +interface Props { + action: + | 'none' + | 'disable' + | 'mark_statuses_as_sensitive' + | 'delete_statuses' + | 'sensitive' + | 'silence' + | 'suspend'; + id: string; + hidden: boolean; +} + +export const ModerationWarning: React.FC = ({ action, id, hidden }) => { + const intl = useIntl(); + + if (hidden) { + return null; + } + + return ( + + + +
+

{intl.formatMessage(messages[action])}

+ + + +
+
+ ); +}; diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx index c091554628..caf7f9bdc1 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.jsx +++ b/app/javascript/mastodon/features/notifications/components/notification.jsx @@ -26,6 +26,7 @@ import { WithRouterPropTypes } from 'mastodon/utils/react_router'; import FollowRequestContainer from '../containers/follow_request_container'; +import { ModerationWarning } from './moderation_warning'; import { RelationshipsSeveranceEvent } from './relationships_severance_event'; import Report from './report'; @@ -40,6 +41,7 @@ const messages = defineMessages({ adminSignUp: { id: 'notification.admin.sign_up', defaultMessage: '{name} signed up' }, adminReport: { id: 'notification.admin.report', defaultMessage: '{name} reported {target}' }, relationshipsSevered: { id: 'notification.relationships_severance_event', defaultMessage: 'Lost connections with {name}' }, + moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'Your have received a moderation warning' }, }); const notificationForScreenReader = (intl, message, timestamp) => { @@ -383,6 +385,27 @@ class Notification extends ImmutablePureComponent { ); } + renderModerationWarning (notification) { + const { intl, unread, hidden } = this.props; + const warning = notification.get('moderation_warning'); + + if (!warning) { + return null; + } + + return ( + +
+
+
+ ); + } + renderAdminSignUp (notification, account, link) { const { intl, unread } = this.props; @@ -456,6 +479,8 @@ class Notification extends ImmutablePureComponent { return this.renderPoll(notification, account); case 'severed_relationships': return this.renderRelationshipsSevered(notification); + case 'moderation_warning': + return this.renderModerationWarning(notification); case 'admin.sign_up': return this.renderAdminSignUp(notification, account, link); case 'admin.report': diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index a1b79881c5..9d127b6b03 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -473,6 +473,15 @@ "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", "notification.mention": "{name} mentioned you", + "notification.moderation-warning.learn_more": "Learn more", + "notification.moderation_warning": "Your have received a moderation warning", + "notification.moderation_warning.action_delete_statuses": "Some of your posts have been removed.", + "notification.moderation_warning.action_disable": "Your account has been disabled.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Some of your posts have been marked as sensitive.", + "notification.moderation_warning.action_none": "Your account has received a moderation warning.", + "notification.moderation_warning.action_sensitive": "Your posts will be marked as sensitive from now on.", + "notification.moderation_warning.action_silence": "Your account has been limited.", + "notification.moderation_warning.action_suspend": "Your account has been suspended.", "notification.own_poll": "Your poll has ended", "notification.poll": "A poll you have voted in has ended", "notification.reblog": "{name} boosted your post", diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js index 7230fabcae..64cddcb666 100644 --- a/app/javascript/mastodon/reducers/notifications.js +++ b/app/javascript/mastodon/reducers/notifications.js @@ -56,6 +56,7 @@ export const notificationToMap = notification => ImmutableMap({ status: notification.status ? notification.status.id : null, report: notification.report ? fromJS(notification.report) : null, event: notification.event ? fromJS(notification.event) : null, + moderation_warning: notification.moderation_warning ? fromJS(notification.moderation_warning) : null, }); const normalizeNotification = (state, notification, usePendingItems) => { diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index a1864a4562..9cb03bedf1 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2180,7 +2180,8 @@ a.account__display-name { } } -.notification__relationships-severance-event { +.notification__relationships-severance-event, +.notification__moderation-warning { display: flex; gap: 16px; color: $secondary-text-color; diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb index 2b5560e2eb..3700ce4cd6 100644 --- a/app/models/admin/account_action.rb +++ b/app/models/admin/account_action.rb @@ -52,7 +52,7 @@ class Admin::AccountAction process_reports! end - process_email! + process_notification! process_queue! end @@ -158,8 +158,11 @@ class Admin::AccountAction queue_suspension_worker! if type == 'suspend' end - def process_email! - UserMailer.warning(target_account.user, warning).deliver_later! if warnable? + def process_notification! + return unless warnable? + + UserMailer.warning(target_account.user, warning).deliver_later! + LocalNotificationWorker.perform_async(target_account.id, warning.id, 'AccountWarning', 'moderation_warning') end def warnable? diff --git a/app/models/admin/status_batch_action.rb b/app/models/admin/status_batch_action.rb index 8a8e2fa378..4a10001935 100644 --- a/app/models/admin/status_batch_action.rb +++ b/app/models/admin/status_batch_action.rb @@ -65,7 +65,8 @@ class Admin::StatusBatchAction statuses.each { |status| Tombstone.find_or_create_by(uri: status.uri, account: status.account, by_moderator: true) } unless target_account.local? end - UserMailer.warning(target_account.user, @warning).deliver_later! if warnable? + process_notification! + RemovalWorker.push_bulk(status_ids) { |status_id| [status_id, { 'preserve' => target_account.local?, 'immediate' => !target_account.local? }] } end @@ -101,7 +102,7 @@ class Admin::StatusBatchAction text: text ) - UserMailer.warning(target_account.user, @warning).deliver_later! if warnable? + process_notification! end def handle_report! @@ -127,6 +128,13 @@ class Admin::StatusBatchAction !report.nil? end + def process_notification! + return unless warnable? + + UserMailer.warning(target_account.user, @warning).deliver_later! + LocalNotificationWorker.perform_async(target_account.id, @warning.id, 'AccountWarning', 'moderation_warning') + end + def warnable? send_email_notification && target_account.local? end diff --git a/app/models/notification.rb b/app/models/notification.rb index b2376c78a3..7e0e62683a 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -57,6 +57,9 @@ class Notification < ApplicationRecord severed_relationships: { filterable: false, }.freeze, + moderation_warning: { + filterable: false, + }.freeze, 'admin.sign_up': { filterable: false, }.freeze, @@ -90,6 +93,7 @@ class Notification < ApplicationRecord belongs_to :poll, inverse_of: false belongs_to :report, inverse_of: false belongs_to :account_relationship_severance_event, inverse_of: false + belongs_to :account_warning, inverse_of: false end validates :type, inclusion: { in: TYPES } @@ -180,7 +184,7 @@ class Notification < ApplicationRecord return unless new_record? case activity_type - when 'Status', 'Follow', 'Favourite', 'FollowRequest', 'Poll', 'Report' + when 'Status', 'Follow', 'Favourite', 'FollowRequest', 'Poll', 'Report', 'AccountWarning' self.from_account_id = activity&.account_id when 'Mention' self.from_account_id = activity&.status&.account_id diff --git a/app/serializers/rest/account_warning_serializer.rb b/app/serializers/rest/account_warning_serializer.rb new file mode 100644 index 0000000000..a0ef341d25 --- /dev/null +++ b/app/serializers/rest/account_warning_serializer.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class REST::AccountWarningSerializer < ActiveModel::Serializer + attributes :id, :action, :text, :status_ids, :created_at + + has_one :target_account, serializer: REST::AccountSerializer + has_one :appeal, serializer: REST::AppealSerializer + + def id + object.id.to_s + end + + def status_ids + object&.status_ids&.map(&:to_s) + end +end diff --git a/app/serializers/rest/appeal_serializer.rb b/app/serializers/rest/appeal_serializer.rb new file mode 100644 index 0000000000..a24cabc272 --- /dev/null +++ b/app/serializers/rest/appeal_serializer.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class REST::AppealSerializer < ActiveModel::Serializer + attributes :text, :state + + def state + if object.approved? + 'approved' + elsif object.rejected? + 'rejected' + else + 'pending' + end + end +end diff --git a/app/serializers/rest/notification_serializer.rb b/app/serializers/rest/notification_serializer.rb index 36a0adfec4..417245d19d 100644 --- a/app/serializers/rest/notification_serializer.rb +++ b/app/serializers/rest/notification_serializer.rb @@ -7,6 +7,7 @@ class REST::NotificationSerializer < ActiveModel::Serializer belongs_to :target_status, key: :status, if: :status_type?, serializer: REST::StatusSerializer belongs_to :report, if: :report_type?, serializer: REST::ReportSerializer belongs_to :account_relationship_severance_event, key: :event, if: :relationship_severance_event?, serializer: REST::AccountRelationshipSeveranceEventSerializer + belongs_to :account_warning, key: :moderation_warning, if: :moderation_warning_event?, serializer: REST::AccountWarningSerializer def id object.id.to_s @@ -23,4 +24,8 @@ class REST::NotificationSerializer < ActiveModel::Serializer def relationship_severance_event? object.type == :severed_relationships end + + def moderation_warning_event? + object.type == :moderation_warning + end end diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index c83e4c017f..e56562c0a5 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -9,6 +9,7 @@ class NotifyService < BaseService update poll status + moderation_warning # TODO: this probably warrants an email notification severed_relationships ).freeze @@ -22,7 +23,7 @@ class NotifyService < BaseService def dismiss? blocked = @recipient.unavailable? - blocked ||= from_self? && @notification.type != :poll && @notification.type != :severed_relationships + blocked ||= from_self? && %i(poll severed_relationships moderation_warning).exclude?(@notification.type) return blocked if message? && from_staff? @@ -75,6 +76,7 @@ class NotifyService < BaseService admin.report poll update + account_warning ).freeze def initialize(notification) diff --git a/spec/models/admin/account_action_spec.rb b/spec/models/admin/account_action_spec.rb index 9bc9f8061d..a9dcf352dc 100644 --- a/spec/models/admin/account_action_spec.rb +++ b/spec/models/admin/account_action_spec.rb @@ -69,22 +69,22 @@ RSpec.describe Admin::AccountAction do end end - it 'creates Admin::ActionLog' do + it 'sends notification, log the action, and closes other reports', :aggregate_failures do + other_report = Fabricate(:report, target_account: target_account) + + emails = [] expect do - subject - end.to change(Admin::ActionLog, :count).by 1 - end + emails = capture_emails { subject } + end.to (change(Admin::ActionLog.where(action: type), :count).by 1) + .and(change { other_report.reload.action_taken? }.from(false).to(true)) - it 'calls process_email!' do - allow(account_action).to receive(:process_email!) - subject - expect(account_action).to have_received(:process_email!) - end + expect(emails).to contain_exactly( + have_attributes( + to: contain_exactly(target_account.user.email) + ) + ) - it 'calls process_reports!' do - allow(account_action).to receive(:process_reports!) - subject - expect(account_action).to have_received(:process_reports!) + expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(target_account.id, anything, 'AccountWarning', 'moderation_warning') end end From 5201882a2389bbd3477440509fe12b2019edb4e7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 26 Apr 2024 12:05:18 +0200 Subject: [PATCH 013/658] New Crowdin Translations (automated) (#30077) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ca.json | 4 ++++ app/javascript/mastodon/locales/da.json | 13 +++++++++++++ app/javascript/mastodon/locales/de.json | 13 +++++++++++++ app/javascript/mastodon/locales/eu.json | 13 +++++++++++++ app/javascript/mastodon/locales/fi.json | 13 +++++++++++++ app/javascript/mastodon/locales/fo.json | 13 +++++++++++++ app/javascript/mastodon/locales/gd.json | 4 ++++ app/javascript/mastodon/locales/gl.json | 13 +++++++++++++ app/javascript/mastodon/locales/he.json | 4 ++++ app/javascript/mastodon/locales/hu.json | 13 +++++++++++++ app/javascript/mastodon/locales/is.json | 13 +++++++++++++ app/javascript/mastodon/locales/it.json | 13 +++++++++++++ app/javascript/mastodon/locales/nl.json | 15 ++++++++++++++- app/javascript/mastodon/locales/nn.json | 9 +++++++++ app/javascript/mastodon/locales/pl.json | 13 +++++++++++++ app/javascript/mastodon/locales/pt-PT.json | 13 +++++++++++++ app/javascript/mastodon/locales/sv.json | 6 +++++- app/javascript/mastodon/locales/zh-CN.json | 13 +++++++++++++ app/javascript/mastodon/locales/zh-TW.json | 13 +++++++++++++ config/locales/de.yml | 4 ++-- config/locales/doorkeeper.pt-PT.yml | 1 + 21 files changed, 212 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 40d9771df1..6dfe06a92e 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Tot i que el teu compte no està blocat, el personal de {domain} ha pensat que és possible que vulguis revisar manualment les sol·licituds de seguiment d’aquests comptes.", "follow_suggestions.curated_suggestion": "Tria de l'equip", "follow_suggestions.dismiss": "No ho tornis a mostrar", + "follow_suggestions.featured_longer": "Triat personalment per l'equip de {domain}", + "follow_suggestions.friends_of_friends_longer": "Popular entre la gent que segueixes", "follow_suggestions.hints.featured": "L'equip de {domain} ha seleccionat aquest perfil.", "follow_suggestions.hints.friends_of_friends": "Aquest perfil és popular entre la gent que seguiu.", "follow_suggestions.hints.most_followed": "Aquest perfil és un dels més seguits a {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Aquest perfil és similar a d'altres que heu seguit recentment.", "follow_suggestions.personalized_suggestion": "Suggeriment personalitzat", "follow_suggestions.popular_suggestion": "Suggeriment popular", + "follow_suggestions.popular_suggestion_longer": "Popular a {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Semblant a perfils que has seguit fa poc", "follow_suggestions.view_all": "Mostra-ho tot", "follow_suggestions.who_to_follow": "A qui seguir", "followed_tags": "Etiquetes seguides", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index a7c8a049ea..a23d537331 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -306,6 +306,8 @@ "follow_requests.unlocked_explanation": "Selvom din konto ikke er låst, synes {domain}-personalet, du måske bør gennemgå disse anmodninger manuelt.", "follow_suggestions.curated_suggestion": "Personaleudvalgt", "follow_suggestions.dismiss": "Vis ikke igen", + "follow_suggestions.featured_longer": "Håndplukket af {domain}-teamet", + "follow_suggestions.friends_of_friends_longer": "Populært blandt personer, som følges", "follow_suggestions.hints.featured": "Denne profil er håndplukket af {domain}-teamet.", "follow_suggestions.hints.friends_of_friends": "Denne profil er populær blandt de personer, som følges.", "follow_suggestions.hints.most_followed": "Denne profil er en af de mest fulgte på {domain}.", @@ -313,6 +315,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Denne profil svarer til de profiler, som senest er blevet fulgt.", "follow_suggestions.personalized_suggestion": "Personligt forslag", "follow_suggestions.popular_suggestion": "Populært forslag", + "follow_suggestions.popular_suggestion_longer": "Populært på {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Svarende til profiler, som for nylig er fulgt", "follow_suggestions.view_all": "Vis alle", "follow_suggestions.who_to_follow": "Hvem, som skal følges", "followed_tags": "Hashtag, som følges", @@ -467,6 +471,15 @@ "notification.follow": "{name} begyndte at følge dig", "notification.follow_request": "{name} har anmodet om at følge dig", "notification.mention": "{name} nævnte dig", + "notification.moderation-warning.learn_more": "Læs mere", + "notification.moderation_warning": "Du er tildelt en moderationsadvarsel", + "notification.moderation_warning.action_delete_statuses": "Nogle af dine indlæg er blevet fjernet.", + "notification.moderation_warning.action_disable": "Din konto er blevet deaktiveret.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nogle af dine indlæg er blevet markeret som sensitive.", + "notification.moderation_warning.action_none": "Din konto er tildelt en moderationsadvarsel.", + "notification.moderation_warning.action_sensitive": "Dine indlæg markeres fra nu af som sensitive.", + "notification.moderation_warning.action_silence": "Din konto er blevet begrænset.", + "notification.moderation_warning.action_suspend": "Din konto er suspenderet.", "notification.own_poll": "Din afstemning er afsluttet", "notification.poll": "En afstemning, hvori du stemte, er slut", "notification.reblog": "{name} boostede dit indlæg", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 8b52cdb3cc..59d3d0965a 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -308,6 +308,8 @@ "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-Team empfohlen", "follow_suggestions.dismiss": "Nicht mehr anzeigen", + "follow_suggestions.featured_longer": "Vom {domain}-Team ausgewählt", + "follow_suggestions.friends_of_friends_longer": "Beliebt bei Leuten, denen du folgst", "follow_suggestions.hints.featured": "Dieses Profil wurde vom {domain}-Team ausgewählt.", "follow_suggestions.hints.friends_of_friends": "Dieses Profil ist bei deinen Followern beliebt.", "follow_suggestions.hints.most_followed": "Dieses Profil ist eines der am meisten gefolgten auf {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Dieses Profil ähnelt den Profilen, denen du in letzter Zeit gefolgt hast.", "follow_suggestions.personalized_suggestion": "Persönliche Empfehlung", "follow_suggestions.popular_suggestion": "Beliebte Empfehlung", + "follow_suggestions.popular_suggestion_longer": "Beliebt auf {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Ähnlich zu Profilen, denen du seit kurzem folgst", "follow_suggestions.view_all": "Alle anzeigen", "follow_suggestions.who_to_follow": "Empfohlene Profile", "followed_tags": "Gefolgte Hashtags", @@ -469,6 +473,15 @@ "notification.follow": "{name} folgt dir", "notification.follow_request": "{name} möchte dir folgen", "notification.mention": "{name} erwähnte dich", + "notification.moderation-warning.learn_more": "Mehr erfahren", + "notification.moderation_warning": "Du wurdest von den Moderator*innen verwarnt", + "notification.moderation_warning.action_delete_statuses": "Einige deiner Beiträge sind entfernt worden.", + "notification.moderation_warning.action_disable": "Dein Konto wurde deaktiviert.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Einige deiner Beiträge wurden mit einer Inhaltswarnung versehen.", + "notification.moderation_warning.action_none": "Dein Konto ist von den Moderator*innen verwarnt worden.", + "notification.moderation_warning.action_sensitive": "Deine zukünftigen Beiträge werden mit einer Inhaltswarnung versehen.", + "notification.moderation_warning.action_silence": "Dein Konto wurde eingeschränkt.", + "notification.moderation_warning.action_suspend": "Dein Konto wurde gesperrt.", "notification.own_poll": "Deine Umfrage ist beendet", "notification.poll": "Eine Umfrage, an der du teilgenommen hast, ist beendet", "notification.reblog": "{name} teilte deinen Beitrag", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 7e2ecf69cd..9fae074878 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Zure kontua blokeatuta ez badago ere, {domain} domeinuko arduradunek uste dute kontu hauetako jarraipen eskaerak agian eskuz begiratu nahiko dituzula.", "follow_suggestions.curated_suggestion": "Domeinuaren iradokizuna", "follow_suggestions.dismiss": "Ez erakutsi berriro", + "follow_suggestions.featured_longer": "{domain} domeinuko taldeak hautaturikoak", + "follow_suggestions.friends_of_friends_longer": "Jarraitzen duzun jendearen artean ezagunak direnak", "follow_suggestions.hints.featured": "Profil hau {domain} domeinuko taldeak eskuz aukeratu du.", "follow_suggestions.hints.friends_of_friends": "Profil hau ezaguna da jarraitzen duzun jendearen artean.", "follow_suggestions.hints.most_followed": "Profil hau {domain} domeinuan gehien jarraitzen den profiletako bat da.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Profil hau duela gutxi jarraitu dituzun profil askoren antzekoa da.", "follow_suggestions.personalized_suggestion": "Iradokizun pertsonalizatua", "follow_suggestions.popular_suggestion": "Iradokizun ezaguna", + "follow_suggestions.popular_suggestion_longer": "{domain} domeinuan ezagunak direnak", + "follow_suggestions.similar_to_recently_followed_longer": "Berriki jarraitu dituzun profilen antzekoa", "follow_suggestions.view_all": "Ikusi denak", "follow_suggestions.who_to_follow": "Zein jarraitu", "followed_tags": "Jarraitutako traolak", @@ -469,6 +473,15 @@ "notification.follow": "{name}(e)k jarraitzen dizu", "notification.follow_request": "{name}(e)k zu jarraitzeko eskaera egin du", "notification.mention": "{name}(e)k aipatu zaitu", + "notification.moderation-warning.learn_more": "Informazio gehiago", + "notification.moderation_warning": "Moderazio-abisu bat jaso duzu", + "notification.moderation_warning.action_delete_statuses": "Argitalpen batzuk kendu dira.", + "notification.moderation_warning.action_disable": "Zure kontua desaktibatua izan da.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Argitalpen batzuk hunkigarri gisa ezarri dira.", + "notification.moderation_warning.action_none": "Kontuak moderazio-abisu bat jaso du.", + "notification.moderation_warning.action_sensitive": "Argitalpenak hunkigarri gisa markatuko dira hemendik aurrera.", + "notification.moderation_warning.action_silence": "Kontua murriztu egin da.", + "notification.moderation_warning.action_suspend": "Kontua itxi da.", "notification.own_poll": "Zure inkesta amaitu da", "notification.poll": "Zuk erantzun duzun inkesta bat bukatu da", "notification.reblog": "{name}(e)k bultzada eman dio zure bidalketari", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 246bb56fcc..5a5031fd14 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Vaikkei tiliäsi ole lukittu, palvelimen {domain} ylläpito on arvioinut, että saatat olla halukas tarkistamaan nämä seuraamispyynnöt erikseen.", "follow_suggestions.curated_suggestion": "Ehdotus ylläpidolta", "follow_suggestions.dismiss": "Älä näytä uudelleen", + "follow_suggestions.featured_longer": "Käsin valinnut palvelimen {domain} tiimi", + "follow_suggestions.friends_of_friends_longer": "Suosittu seuraamiesi ihmisten keskuudessa", "follow_suggestions.hints.featured": "Tämän profiilin on valinnut palvelimen {domain} tiimi.", "follow_suggestions.hints.friends_of_friends": "Seuraamasi käyttäjät suosivat tätä profiilia.", "follow_suggestions.hints.most_followed": "Tämä profiili on palvelimen {domain} seuratuimpia.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Tämä profiili on samankaltainen kuin profiilit, joita olet viimeksi seurannut.", "follow_suggestions.personalized_suggestion": "Mukautettu ehdotus", "follow_suggestions.popular_suggestion": "Suosittu ehdotus", + "follow_suggestions.popular_suggestion_longer": "Suosittu palvelimella {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Samankaltainen kuin äskettäin seuraamasi profiilit", "follow_suggestions.view_all": "Näytä kaikki", "follow_suggestions.who_to_follow": "Ehdotuksia seurattavaksi", "followed_tags": "Seuratut aihetunnisteet", @@ -469,6 +473,15 @@ "notification.follow": "{name} seurasi sinua", "notification.follow_request": "{name} on pyytänyt lupaa saada seurata sinua", "notification.mention": "{name} mainitsi sinut", + "notification.moderation-warning.learn_more": "Lue lisää", + "notification.moderation_warning": "Olet saanut moderointivaroituksen", + "notification.moderation_warning.action_delete_statuses": "Jotkin julkaisusi on poistettu.", + "notification.moderation_warning.action_disable": "Tilisi on poistettu käytöstä.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Jotkin julkaisusi on merkitty arkaluonteisiksi.", + "notification.moderation_warning.action_none": "Tilisi on saanut moderointivaroituksen.", + "notification.moderation_warning.action_sensitive": "Tästä lähtien julkaisusi merkitään arkaluonteisiksi.", + "notification.moderation_warning.action_silence": "Tiliäsi on rajoitettu.", + "notification.moderation_warning.action_suspend": "Tilisi on jäädytetty.", "notification.own_poll": "Äänestyksesi on päättynyt", "notification.poll": "Kysely, johon osallistuit, on päättynyt", "notification.reblog": "{name} tehosti julkaisuasi", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 68faf6d81f..77257413fd 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Sjálvt um konta tín ikki er læst, so hugsa {domain} starvsfólkini, at tú kanska hevur hug at kanna umbønir um at fylgja frá hesum kontum við hond.", "follow_suggestions.curated_suggestion": "Val hjá ábyrgdarfólki", "follow_suggestions.dismiss": "Lat vera við at vísa", + "follow_suggestions.featured_longer": "Vald burturúr av {domain} toyminum", + "follow_suggestions.friends_of_friends_longer": "Vælumtókt millum fólk, sum tú fylgir", "follow_suggestions.hints.featured": "Hesin vangin er úrvaldur av toyminum handan {domain}.", "follow_suggestions.hints.friends_of_friends": "Hesin vangin er vælumtóktur millum tey, tú fylgir.", "follow_suggestions.hints.most_followed": "Hesin vangin er ein av teimum, sum er mest fylgdur á {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Hesin vangin líkist teimum, sum tú nýliga hevur fylgt.", "follow_suggestions.personalized_suggestion": "Persónligt uppskot", "follow_suggestions.popular_suggestion": "Vælumtókt uppskot", + "follow_suggestions.popular_suggestion_longer": "Vælumtókt á {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Líkist vangum, sum tú nýliga hevur fylgt", "follow_suggestions.view_all": "Vís øll", "follow_suggestions.who_to_follow": "Hvørji tú átti at fylgt", "followed_tags": "Fylgd frámerki", @@ -469,6 +473,15 @@ "notification.follow": "{name} fylgdi tær", "notification.follow_request": "{name} biður um at fylgja tær", "notification.mention": "{name} nevndi teg", + "notification.moderation-warning.learn_more": "Lær meira", + "notification.moderation_warning": "Tú hevur móttikið eina umsjónarávarðing", + "notification.moderation_warning.action_delete_statuses": "Onkrir av tínum postum eru strikaðir.", + "notification.moderation_warning.action_disable": "Konta tín er gjørd óvirkin.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nakrir av postum tínum eru merktir sum viðkvæmir.", + "notification.moderation_warning.action_none": "Konta tín hevur móttikið eina umsjónarávarðing.", + "notification.moderation_warning.action_sensitive": "Postar tínir verða merktir sum viðkvæmir frá nú av.", + "notification.moderation_warning.action_silence": "Konta tín er avmarkað.", + "notification.moderation_warning.action_suspend": "Konta tín er ógildað.", "notification.own_poll": "Tín atkvøðugreiðsla er endað", "notification.poll": "Ein atkvøðugreiðsla, har tú hevur atkvøtt, er endað", "notification.reblog": "{name} lyfti tín post", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index 8ab515e1a8..9e79793de1 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -297,6 +297,7 @@ "filter_modal.select_filter.subtitle": "Cleachd roinn-seòrsa a tha ann no cruthaich tè ùr", "filter_modal.select_filter.title": "Criathraich am post seo", "filter_modal.title.status": "Criathraich post", + "filtered_notifications_banner.mentions": "{count, plural, one {iomradh} two {iomradh} few {iomraidhean} other {iomradh}}", "filtered_notifications_banner.pending_requests": "{count, plural, =0 {Chan eil brath ann o dhaoine} one {Tha brathan ann o # neach} two {Tha brathan ann o # neach} few {Tha brathan ann o # daoine} other {Tha brathan ann o # duine}} air a bheil thu eòlach ’s dòcha", "filtered_notifications_banner.title": "Brathan criathraichte", "firehose.all": "Na h-uile", @@ -307,6 +308,7 @@ "follow_requests.unlocked_explanation": "Ged nach eil an cunntas agad glaiste, tha sgioba {domain} dhen bheachd gum b’ fheàirrde thu lèirmheas a dhèanamh air na h-iarrtasan leantainn o na cunntasan seo a làimh.", "follow_suggestions.curated_suggestion": "Roghainn an sgioba", "follow_suggestions.dismiss": "Na seall seo a-rithist", + "follow_suggestions.friends_of_friends_longer": "Fèill mhòr am measg nan daoine a leanas tu", "follow_suggestions.hints.featured": "Chaidh a’ phròifil seo a thaghadh le sgioba {domain} a làimh.", "follow_suggestions.hints.friends_of_friends": "Tha fèill mhòr air a’ phròifil seo am measg nan daoine a leanas tu.", "follow_suggestions.hints.most_followed": "Tha a’ phròifil seo am measg an fheadhainn a leanar as trice air {domain}.", @@ -314,6 +316,7 @@ "follow_suggestions.hints.similar_to_recently_followed": "Tha a’ phròifil seo coltach ris na pròifilean air an lean thu o chionn goirid.", "follow_suggestions.personalized_suggestion": "Moladh pearsanaichte", "follow_suggestions.popular_suggestion": "Moladh air a bheil fèill mhòr", + "follow_suggestions.popular_suggestion_longer": "Fèill mhòr air {domain}", "follow_suggestions.view_all": "Seall na h-uile", "follow_suggestions.who_to_follow": "Molaidhean leantainn", "followed_tags": "Tagaichean hais ’gan leantainn", @@ -468,6 +471,7 @@ "notification.follow": "Tha {name} ’gad leantainn a-nis", "notification.follow_request": "Dh’iarr {name} ’gad leantainn", "notification.mention": "Thug {name} iomradh ort", + "notification.moderation-warning.learn_more": "Barrachd fiosrachaidh", "notification.own_poll": "Thàinig an cunntas-bheachd agad gu crìoch", "notification.poll": "Thàinig cunntas-bheachd sa bhòt thu gu crìoch", "notification.reblog": "Bhrosnaich {name} am post agad", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 901bca7498..49802ac488 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Malia que a túa conta non é privada, a administración de {domain} pensou que quizabes terías que revisar de xeito manual as solicitudes de seguiminto.", "follow_suggestions.curated_suggestion": "Suxestións do Servidor", "follow_suggestions.dismiss": "Non mostrar máis", + "follow_suggestions.featured_longer": "Elección persoal do equipo de {domain}", + "follow_suggestions.friends_of_friends_longer": "Popular entre as persoas que sigues", "follow_suggestions.hints.featured": "Este perfil foi escollido pola administración de {domain}.", "follow_suggestions.hints.friends_of_friends": "Este perfil é popular entre as persoas que segues.", "follow_suggestions.hints.most_followed": "Este perfil é un dos máis seguidos en {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Este perfil ten semellanzas cos perfís que ti seguiches últimamente.", "follow_suggestions.personalized_suggestion": "Suxestión personalizada", "follow_suggestions.popular_suggestion": "Suxestión popular", + "follow_suggestions.popular_suggestion_longer": "Popular en {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Perfís semellantes aos que seguiches recentemente", "follow_suggestions.view_all": "Ver todas", "follow_suggestions.who_to_follow": "A quen seguir", "followed_tags": "Cancelos seguidos", @@ -469,6 +473,15 @@ "notification.follow": "{name} comezou a seguirte", "notification.follow_request": "{name} solicitou seguirte", "notification.mention": "{name} mencionoute", + "notification.moderation-warning.learn_more": "Saber máis", + "notification.moderation_warning": "Recibiches unha advertencia da moderación", + "notification.moderation_warning.action_delete_statuses": "Algunha das túas publicacións foron eliminadas.", + "notification.moderation_warning.action_disable": "A túa conta foi desactivada.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algunha das túas publicacións foron marcadas como sensibles.", + "notification.moderation_warning.action_none": "A túa conta recibeu unha advertencia da moderación.", + "notification.moderation_warning.action_sensitive": "De agora en diante as túas publicacións van ser marcadas como sensibles.", + "notification.moderation_warning.action_silence": "A túa conta foi limitada.", + "notification.moderation_warning.action_suspend": "A túa conta foi suspendida.", "notification.own_poll": "A túa enquisa rematou", "notification.poll": "Rematou a enquisa na que votaches", "notification.reblog": "{name} compartiu a túa publicación", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index d696186bf5..0b66a27fa9 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "למרות שחשבונך אינו נעול, צוות {domain} חושב שאולי כדאי לוודא את בקשות המעקב האלה ידנית.", "follow_suggestions.curated_suggestion": "בחירת הצוות", "follow_suggestions.dismiss": "לא להציג שוב", + "follow_suggestions.featured_longer": "נבחר ידנית על ידי הצוות של {domain}", + "follow_suggestions.friends_of_friends_longer": "פופולרי בין הנעקבים שלך", "follow_suggestions.hints.featured": "החשבון הזה נבחר אישית על ידי צוות {domain}.", "follow_suggestions.hints.friends_of_friends": "חשבון זה פופולרי בין הנעקבים שלך.", "follow_suggestions.hints.most_followed": "חשבון זה הוא מבין הנעקבים ביותר בשרת {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "חשבון זה דומה לחשבונות אחרים שאחריהם התחלת לעקוב לאחרונה.", "follow_suggestions.personalized_suggestion": "הצעות מותאמות אישית", "follow_suggestions.popular_suggestion": "הצעה פופולרית", + "follow_suggestions.popular_suggestion_longer": "פופולרי בקהילת {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "דומה למשתמשות.ים שעקבת אחריהן.ם לאחרונה", "follow_suggestions.view_all": "צפיה בכל", "follow_suggestions.who_to_follow": "אחרי מי לעקוב", "followed_tags": "התגיות שהחשבון שלך עוקב אחריהן", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 16dcea642d..42ce842585 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Bár a fiókod nincs zárolva, a(z) {domain} csapata úgy gondolta, hogy talán kézzel szeretnéd ellenőrizni ezen fiókok követési kéréseit.", "follow_suggestions.curated_suggestion": "A stáb választása", "follow_suggestions.dismiss": "Ne jelenjen meg újra", + "follow_suggestions.featured_longer": "A {domain} csapata által kézzel kiválasztott", + "follow_suggestions.friends_of_friends_longer": "Népszerű az Ön által követett emberek körében", "follow_suggestions.hints.featured": "Ezt a profilt a(z) {domain} csapata választotta ki.", "follow_suggestions.hints.friends_of_friends": "Ez a profil népszerű az általad követett emberek körében.", "follow_suggestions.hints.most_followed": "Ez a profil a leginkább követett a(z) {domain} oldalon.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Ez a profil hasonló azokhoz a profilokhoz, melyeket nemrég kezdtél el követni.", "follow_suggestions.personalized_suggestion": "Személyre szabott javaslat", "follow_suggestions.popular_suggestion": "Népszerű javaslat", + "follow_suggestions.popular_suggestion_longer": "Népszerű itt: {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Hasonló profilok, melyeket nemrég követett", "follow_suggestions.view_all": "Összes megtekintése", "follow_suggestions.who_to_follow": "Kit érdemes követni", "followed_tags": "Követett hashtagek", @@ -469,6 +473,15 @@ "notification.follow": "{name} követ téged", "notification.follow_request": "{name} követni szeretne téged", "notification.mention": "{name} megemlített", + "notification.moderation-warning.learn_more": "További információk", + "notification.moderation_warning": "Moderációs figyelmeztetést kaptál", + "notification.moderation_warning.action_delete_statuses": "Néhány bejegyzésedet eltávolították.", + "notification.moderation_warning.action_disable": "A fiókod le van tiltva.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Néhány bejegyzésedet kényesnek jelölték.", + "notification.moderation_warning.action_none": "A fiókod moderációs figyelmeztetést kapott.", + "notification.moderation_warning.action_sensitive": "A bejegyzéseid mostantól érzékenynek lesznek jelölve.", + "notification.moderation_warning.action_silence": "A fiókod korlátozásra került.", + "notification.moderation_warning.action_suspend": "A fiókod felfüggesztésre került.", "notification.own_poll": "A szavazásod véget ért", "notification.poll": "Egy szavazás, melyben részt vettél, véget ért", "notification.reblog": "{name} megtolta a bejegyzésedet", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 435f98f30f..f5bf7c3281 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Jafnvel þótt aðgangurinn þinn sé ekki læstur, hafa umsjónarmenn {domain} ímyndað sér að þú gætir viljað yfirfara handvirkt fylgjendabeiðnir frá þessum notendum.", "follow_suggestions.curated_suggestion": "Úrval starfsfólks", "follow_suggestions.dismiss": "Ekki birta þetta aftur", + "follow_suggestions.featured_longer": "Handvalið af {domain}-teyminu", + "follow_suggestions.friends_of_friends_longer": "Vinsælt hjá fólki sem þú fylgist með", "follow_suggestions.hints.featured": "Þetta notandasnið hefur verið handvalið af {domain}-teyminu.", "follow_suggestions.hints.friends_of_friends": "Þetta notandasnið er vinsælt hjá fólki sem þú fylgist með.", "follow_suggestions.hints.most_followed": "Þetta notandasnið er eitt af þeim sem mest er fylgst með á {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Þetta notandasnið er líkt þeim sniðum sem þú hefur valið að fylgjast með að undanförnu.", "follow_suggestions.personalized_suggestion": "Persónuaðlöguð tillaga", "follow_suggestions.popular_suggestion": "Vinsæl tillaga", + "follow_suggestions.popular_suggestion_longer": "Vinsælt á {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Svipar til notenda sem þú hefur nýlega farið að fylgjast með", "follow_suggestions.view_all": "Skoða allt", "follow_suggestions.who_to_follow": "Hverjum á að fylgjast með", "followed_tags": "Myllumerki sem fylgst er með", @@ -469,6 +473,15 @@ "notification.follow": "{name} fylgist með þér", "notification.follow_request": "{name} hefur beðið um að fylgjast með þér", "notification.mention": "{name} minntist á þig", + "notification.moderation-warning.learn_more": "Kanna nánar", + "notification.moderation_warning": "Þú hefur fengið aðvörun frá umsjónarmanni", + "notification.moderation_warning.action_delete_statuses": "Sumar færslurnar þínar hafa verið fjarlægðar.", + "notification.moderation_warning.action_disable": "Aðgangurinn þinn hefur verið gerður óvirkur.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Sumar færslurnar þínar hafa verið merktar sem viðkvæmt efni.", + "notification.moderation_warning.action_none": "Aðgangurinn þinn hefur fengið aðvörun frá umsjónarmanni.", + "notification.moderation_warning.action_sensitive": "Færslur þínar á verða héðan í frá merktar sem viðkvæmar.", + "notification.moderation_warning.action_silence": "Notandaaðgangurinn þinn hefur verið takmarkaður.", + "notification.moderation_warning.action_suspend": "Notandaaðgangurinn þinn hefur verið settur í frysti.", "notification.own_poll": "Könnuninni þinni er lokið", "notification.poll": "Könnun sem þú tókst þátt í er lokið", "notification.reblog": "{name} endurbirti færsluna þína", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index fcfd09d75f..8ab5db1b17 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Anche se il tuo profilo non è privato, lo staff di {domain} ha pensato che potresti voler revisionare manualmente le richieste di seguirti da questi profili.", "follow_suggestions.curated_suggestion": "Scelta personale", "follow_suggestions.dismiss": "Non visualizzare più", + "follow_suggestions.featured_longer": "Selezionato personalmente dal team di {domain}", + "follow_suggestions.friends_of_friends_longer": "Popolare tra le persone che segui", "follow_suggestions.hints.featured": "Questo profilo è stato selezionato personalmente dal team di {domain}.", "follow_suggestions.hints.friends_of_friends": "Questo profilo è popolare tra le persone che segui.", "follow_suggestions.hints.most_followed": "Questo profilo è uno dei più seguiti su {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Questo profilo è simile ai profili che hai seguito più recentemente.", "follow_suggestions.personalized_suggestion": "Suggerimenti personalizzati", "follow_suggestions.popular_suggestion": "Suggerimento frequente", + "follow_suggestions.popular_suggestion_longer": "Popolare su {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Simile ai profili che hai seguito di recente", "follow_suggestions.view_all": "Vedi tutto", "follow_suggestions.who_to_follow": "Chi seguire", "followed_tags": "Hashtag seguiti", @@ -469,6 +473,15 @@ "notification.follow": "{name} ha iniziato a seguirti", "notification.follow_request": "{name} ha richiesto di seguirti", "notification.mention": "{name} ti ha menzionato", + "notification.moderation-warning.learn_more": "Scopri di più", + "notification.moderation_warning": "Hai ricevuto un avviso di moderazione", + "notification.moderation_warning.action_delete_statuses": "Alcuni dei tuoi post sono stati rimossi.", + "notification.moderation_warning.action_disable": "Il tuo account è stato disattivato.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Alcuni dei tuoi post sono stati contrassegnati come sensibili.", + "notification.moderation_warning.action_none": "Il tuo account ha ricevuto un avviso di moderazione.", + "notification.moderation_warning.action_sensitive": "I tuoi post d'ora in poi saranno contrassegnati come sensibili.", + "notification.moderation_warning.action_silence": "Il tuo account è stato limitato.", + "notification.moderation_warning.action_suspend": "Il tuo account è stato sospeso.", "notification.own_poll": "Il tuo sondaggio è terminato", "notification.poll": "Un sondaggio in cui hai votato è terminato", "notification.reblog": "{name} ha rebloggato il tuo post", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 46d1f97835..1958e4a6a0 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -308,13 +308,17 @@ "follow_requests.unlocked_explanation": "Ook al is jouw account niet besloten, de medewerkers van {domain} denken dat jij misschien de volgende volgverzoeken handmatig wil controleren.", "follow_suggestions.curated_suggestion": "Speciaal geselecteerd", "follow_suggestions.dismiss": "Niet meer weergeven", - "follow_suggestions.hints.featured": "Deze gebruiker is geselecteerd door het team van {domain}.", + "follow_suggestions.featured_longer": "Handmatig geselecteerd door het team van {domain}", + "follow_suggestions.friends_of_friends_longer": "Populair onder mensen die je volgt", + "follow_suggestions.hints.featured": "Deze gebruiker is handmatig geselecteerd door het team van {domain}.", "follow_suggestions.hints.friends_of_friends": "Deze gebruiker is populair onder de mensen die jij volgt.", "follow_suggestions.hints.most_followed": "Deze gebruiker is een van de meest gevolgde gebruikers op {domain}.", "follow_suggestions.hints.most_interactions": "Deze gebruiker is de laatste tijd erg populair op {domain}.", "follow_suggestions.hints.similar_to_recently_followed": "Deze gebruiker is vergelijkbaar met gebruikers die je recentelijk hebt gevolgd.", "follow_suggestions.personalized_suggestion": "Gepersonaliseerde aanbeveling", "follow_suggestions.popular_suggestion": "Populaire aanbeveling", + "follow_suggestions.popular_suggestion_longer": "Populair op {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Vergelijkbaar met accounts die je recentelijk bent gaan volgen", "follow_suggestions.view_all": "Alles weergeven", "follow_suggestions.who_to_follow": "Wie te volgen", "followed_tags": "Gevolgde hashtags", @@ -469,6 +473,15 @@ "notification.follow": "{name} volgt jou nu", "notification.follow_request": "{name} wil jou graag volgen", "notification.mention": "{name} vermeldde jou", + "notification.moderation-warning.learn_more": "Meer informatie", + "notification.moderation_warning": "Je hebt een moderatie-waarschuwing ontvangen", + "notification.moderation_warning.action_delete_statuses": "Sommige van je berichten zijn verwijderd.", + "notification.moderation_warning.action_disable": "Je account is uitgeschakeld.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Sommige van je berichten zijn gemarkeerd als gevoelig.", + "notification.moderation_warning.action_none": "Jouw account heeft een moderatie-waarschuwing ontvangen.", + "notification.moderation_warning.action_sensitive": "Je berichten worden vanaf nu als gevoelig gemarkeerd.", + "notification.moderation_warning.action_silence": "Jouw account is beperkt.", + "notification.moderation_warning.action_suspend": "Jouw account is opgeschort.", "notification.own_poll": "Jouw peiling is beëindigd", "notification.poll": "Een peiling waaraan jij hebt meegedaan is beëindigd", "notification.reblog": "{name} boostte jouw bericht", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 2cfb0d1247..14b355233b 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -468,6 +468,15 @@ "notification.follow": "{name} fylgde deg", "notification.follow_request": "{name} har bedt om å fylgja deg", "notification.mention": "{name} nemnde deg", + "notification.moderation-warning.learn_more": "Lær meir", + "notification.moderation_warning": "Du har mottatt ei moderasjonsåtvaring", + "notification.moderation_warning.action_delete_statuses": "Nokre av innlegga dine har blitt fjerna.", + "notification.moderation_warning.action_disable": "Kontoen din har blitt deaktivert.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nokre av innlegga dine har blitt markert som sensitive.", + "notification.moderation_warning.action_none": "Kontoen din har mottatt ei moderasjonsåtvaring.", + "notification.moderation_warning.action_sensitive": "Innlegga dine vil bli markerte som sensitive frå no av.", + "notification.moderation_warning.action_silence": "Kontoen din har blitt avgrensa.", + "notification.moderation_warning.action_suspend": "Kontoen din har blitt suspendert.", "notification.own_poll": "Rundspørjinga di er ferdig", "notification.poll": "Ei rundspørjing du har røysta i er ferdig", "notification.reblog": "{name} framheva innlegget ditt", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 72f1ba58f5..b763f740a2 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Mimo że Twoje konto nie jest zablokowane, zespół {domain} uznał że możesz chcieć ręcznie przejrzeć prośby o możliwość obserwacji.", "follow_suggestions.curated_suggestion": "Wybrane przez personel", "follow_suggestions.dismiss": "Nie pokazuj ponownie", + "follow_suggestions.featured_longer": "Wybrane przez zespół {domain}", + "follow_suggestions.friends_of_friends_longer": "Popularni wśród ludzi których obserwujesz", "follow_suggestions.hints.featured": "Ten profil został wybrany przez zespół {domain}.", "follow_suggestions.hints.friends_of_friends": "Ten profil jest popularny w gronie użytkowników, których obserwujesz.", "follow_suggestions.hints.most_followed": "Ten profil jest jednym z najczęściej obserwowanych na {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Ten profil jest podobny do profili ostatnio przez ciebie zaobserwowanych.", "follow_suggestions.personalized_suggestion": "Sugestia spersonalizowana", "follow_suggestions.popular_suggestion": "Sugestia popularna", + "follow_suggestions.popular_suggestion_longer": "Popularni na {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Podobne do ostatnio zaobserwowanych przez ciebie profilów", "follow_suggestions.view_all": "Pokaż wszystkie", "follow_suggestions.who_to_follow": "Kogo obserwować", "followed_tags": "Obserwowane hasztagi", @@ -469,6 +473,15 @@ "notification.follow": "{name} obserwuje Cię", "notification.follow_request": "{name} chce cię zaobserwować", "notification.mention": "Wspomniało o Tobie przez {name}", + "notification.moderation-warning.learn_more": "Dowiedz się więcej", + "notification.moderation_warning": "Otrzymałeś/-łaś ostrzeżenie moderacyjne", + "notification.moderation_warning.action_delete_statuses": "Niektóre twoje wpisy zostały usunięte.", + "notification.moderation_warning.action_disable": "Twoje konto zostało wyłączone.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Niektóre twoje wpisy zostały oznaczone jako wrażliwe.", + "notification.moderation_warning.action_none": "Twoje konto otrzymało ostrzeżenie moderacyjne.", + "notification.moderation_warning.action_sensitive": "Twoje wpisy będą od teraz oznaczane jako wrażliwe.", + "notification.moderation_warning.action_silence": "Twoje konto zostało ograniczone.", + "notification.moderation_warning.action_suspend": "Twoje konto zostało zawieszone.", "notification.own_poll": "Twoje głosowanie zakończyło się", "notification.poll": "Głosowanie w którym brałeś(-aś) udział zakończyło się", "notification.reblog": "Twój post został podbity przez {name}", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 7e98cde5fa..70903065da 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Apesar de a sua não ser privada, a administração de {domain} pensa que poderá querer rever manualmente os pedidos de seguimento dessas contas.", "follow_suggestions.curated_suggestion": "Escolha da equipe", "follow_suggestions.dismiss": "Não mostrar novamente", + "follow_suggestions.featured_longer": "Escolhido a dedo pela equipa de {domain}", + "follow_suggestions.friends_of_friends_longer": "Popular entre as pessoas que segue", "follow_suggestions.hints.featured": "Este perfil foi escolhido a dedo pela equipe {domain}.", "follow_suggestions.hints.friends_of_friends": "Este perfil é popular entre as pessoas que você segue.", "follow_suggestions.hints.most_followed": "Este perfil é um dos mais seguidos no {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Este perfil é semelhante aos perfis que você seguiu mais recentemente.", "follow_suggestions.personalized_suggestion": "Sugestão personalizada", "follow_suggestions.popular_suggestion": "Sugestão popular", + "follow_suggestions.popular_suggestion_longer": "Popular em {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Semelhantes aos perfis que seguiu recentemente", "follow_suggestions.view_all": "Ver tudo", "follow_suggestions.who_to_follow": "Quem seguir", "followed_tags": "Hashtags seguidas", @@ -469,6 +473,15 @@ "notification.follow": "{name} começou a seguir-te", "notification.follow_request": "{name} pediu para segui-lo", "notification.mention": "{name} mencionou-te", + "notification.moderation-warning.learn_more": "Saber mais", + "notification.moderation_warning": "Recebeu um aviso de moderação", + "notification.moderation_warning.action_delete_statuses": "Algumas das suas publicações foram removidas.", + "notification.moderation_warning.action_disable": "A sua conta foi desativada.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algumas das suas publicações foram assinaladas como sensíveis.", + "notification.moderation_warning.action_none": "A sua conta recebeu um aviso de moderação.", + "notification.moderation_warning.action_sensitive": "As suas publicações serão, a partir de agora, assinaladas como sensíveis.", + "notification.moderation_warning.action_silence": "A sua conta foi limitada.", + "notification.moderation_warning.action_suspend": "A sua conta foi suspensa.", "notification.own_poll": "A sua votação terminou", "notification.poll": "Uma votação em que participaste chegou ao fim", "notification.reblog": "{name} reforçou a tua publicação", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 2b9f0a51b9..c2dd5297db 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -297,7 +297,6 @@ "filter_modal.select_filter.subtitle": "Använd en befintlig kategori eller skapa en ny", "filter_modal.select_filter.title": "Filtrera detta inlägg", "filter_modal.title.status": "Filtrera ett inlägg", - "filtered_notifications_banner.mentions": "{count, plural, one {mention} other {mentions}}", "filtered_notifications_banner.pending_requests": "Aviseringar från {count, plural, =0 {ingen} one {en person} other {# personer}} du kanske känner", "filtered_notifications_banner.title": "Filtrerade aviseringar", "firehose.all": "Allt", @@ -469,6 +468,11 @@ "notification.follow": "{name} följer dig", "notification.follow_request": "{name} har begärt att följa dig", "notification.mention": "{name} nämnde dig", + "notification.moderation-warning.learn_more": "Läs mer", + "notification.moderation_warning.action_delete_statuses": "Några av dina inlägg har tagits bort.", + "notification.moderation_warning.action_disable": "Ditt konto har inaktiverats.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Några av dina inlägg har markerats som känsliga.", + "notification.moderation_warning.action_silence": "Ditt konto har begränsats.", "notification.own_poll": "Din röstning har avslutats", "notification.poll": "En omröstning du röstat i har avslutats", "notification.reblog": "{name} boostade ditt inlägg", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 83fa723388..ab6fe0bd70 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "尽管你没有锁嘟,但是 {domain} 的工作人员认为你也许会想手动审核审核这些账号的关注请求。", "follow_suggestions.curated_suggestion": "站务人员精选", "follow_suggestions.dismiss": "不再显示", + "follow_suggestions.featured_longer": "由 {domain} 管理团队精选", + "follow_suggestions.friends_of_friends_longer": "在你关注的人中很受欢迎", "follow_suggestions.hints.featured": "该用户已被 {domain} 管理团队精选。", "follow_suggestions.hints.friends_of_friends": "该用户在您关注的人中很受欢迎。", "follow_suggestions.hints.most_followed": "该用户是 {domain} 上关注度最高的用户之一。", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "该用户与您最近关注的用户类似。", "follow_suggestions.personalized_suggestion": "个性化建议", "follow_suggestions.popular_suggestion": "热门建议", + "follow_suggestions.popular_suggestion_longer": "在 {domain} 上很受欢迎", + "follow_suggestions.similar_to_recently_followed_longer": "与你近期关注的用户相似", "follow_suggestions.view_all": "查看全部", "follow_suggestions.who_to_follow": "推荐关注", "followed_tags": "关注的话题标签", @@ -469,6 +473,15 @@ "notification.follow": "{name} 开始关注你", "notification.follow_request": "{name} 向你发送了关注请求", "notification.mention": "{name} 提及了你", + "notification.moderation-warning.learn_more": "了解更多", + "notification.moderation_warning": "你收到了一条管理警告", + "notification.moderation_warning.action_delete_statuses": "你的一些嘟文已被移除。", + "notification.moderation_warning.action_disable": "你的账号已被禁用。", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "你的一些嘟文已被标记为敏感内容。", + "notification.moderation_warning.action_none": "你的账号收到了管理警告。", + "notification.moderation_warning.action_sensitive": "今后你的嘟文都会被标记为敏感内容。", + "notification.moderation_warning.action_silence": "你的账号已被限制。", + "notification.moderation_warning.action_suspend": "你的账号已被封禁.", "notification.own_poll": "你的投票已经结束", "notification.poll": "你参与的一个投票已经结束", "notification.reblog": "{name} 转发了你的嘟文", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 33a7070a51..f00d62c076 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "即便您的帳號未被鎖定,{domain} 的管理員認為您可能想要自己審核這些帳號的跟隨請求。", "follow_suggestions.curated_suggestion": "精選內容", "follow_suggestions.dismiss": "不再顯示", + "follow_suggestions.featured_longer": "{domain} 團隊精選", + "follow_suggestions.friends_of_friends_longer": "受您跟隨之使用者愛戴的風雲人物", "follow_suggestions.hints.featured": "這個個人檔案是 {domain} 管理團隊精心挑選。", "follow_suggestions.hints.friends_of_friends": "這個個人檔案於您跟隨的帳號中很受歡迎。", "follow_suggestions.hints.most_followed": "這個個人檔案是 {domain} 中最受歡迎的帳號之一。", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "這個個人檔案與您最近跟隨之帳號類似。", "follow_suggestions.personalized_suggestion": "個人化推薦", "follow_suggestions.popular_suggestion": "熱門推薦", + "follow_suggestions.popular_suggestion_longer": "{domain} 上的人氣王", + "follow_suggestions.similar_to_recently_followed_longer": "與您近日跟隨相近之帳號", "follow_suggestions.view_all": "檢視全部", "follow_suggestions.who_to_follow": "推薦跟隨帳號", "followed_tags": "已跟隨主題標籤", @@ -469,6 +473,15 @@ "notification.follow": "{name} 已跟隨您", "notification.follow_request": "{name} 要求跟隨您", "notification.mention": "{name} 已提到您", + "notification.moderation-warning.learn_more": "了解更多", + "notification.moderation_warning": "您已收到管理員警告", + "notification.moderation_warning.action_delete_statuses": "某些您的嘟文已被刪除。", + "notification.moderation_warning.action_disable": "您的帳號已被停用。", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "某些您的嘟文已被標記為敏感內容。", + "notification.moderation_warning.action_none": "您的帳號已收到管理員警告。", + "notification.moderation_warning.action_sensitive": "即日起,您的嘟文將會被標記為敏感內容。", + "notification.moderation_warning.action_silence": "您的帳號已被限制。", + "notification.moderation_warning.action_suspend": "您的帳號已被停權。", "notification.own_poll": "您的投票已結束", "notification.poll": "您曾投過的投票已經結束", "notification.reblog": "{name} 已轉嘟您的嘟文", diff --git a/config/locales/de.yml b/config/locales/de.yml index 27073ff9ee..923682ea12 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1449,7 +1449,7 @@ de: cooldown: Nach dem Umzug wird es eine Weile dauern, bis du erneut umziehen darfst disabled_account: Dein altes Konto ist nur noch eingeschränkt nutzbar. Du kannst jedoch deine Daten exportieren und das Konto wieder reaktivieren. followers: Alle Follower werden vom alten zum neuen Konto übertragen - only_redirect_html: Alternativ kannst du auch nur eine Weiterleitung zu deinem neuen Profil einrichten, ohne die Follower zu übertragen. + only_redirect_html: Alternativ kannst du auch nur eine Weiterleitung zu deinem neuen Konto einrichten, ohne die Follower zu übertragen. other_data: Keine anderen Daten werden automatisch zum neuen Konto übertragen redirect: Dein altes Konto wird einen Hinweis erhalten, dass du umgezogen bist. Außerdem wird das Profil von Suchanfragen ausgeschlossen moderation: @@ -1845,7 +1845,7 @@ de: mark_statuses_as_sensitive: Deine Beiträge von %{acct} wurden mit einer Inhaltswarnung versehen none: Warnung für %{acct} sensitive: Deine Beiträge von %{acct} werden künftig mit einer Inhaltswarnung versehen - silence: Dein Konto %{acct} wurde stummgeschaltet + silence: Dein Konto %{acct} wurde eingeschränkt suspend: Dein Konto %{acct} wurde gesperrt title: delete_statuses: Beiträge entfernt diff --git a/config/locales/doorkeeper.pt-PT.yml b/config/locales/doorkeeper.pt-PT.yml index 31f6e46278..0457190cda 100644 --- a/config/locales/doorkeeper.pt-PT.yml +++ b/config/locales/doorkeeper.pt-PT.yml @@ -174,6 +174,7 @@ pt-PT: read:filters: ver os seus filtros read:follows: ver quem você segue read:lists: ver as suas listas + read:me: ler apenas as informações básicas da sua conta read:mutes: ver os utilizadores que silenciou read:notifications: ver as suas notificações read:reports: ver as suas denúncias From e8455948780d4c4b8d2d42fa1115fa7f7df87f7f Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 26 Apr 2024 14:42:06 +0200 Subject: [PATCH 014/658] Fix moderator account being exposed in account moderation notification (#30082) --- app/models/notification.rb | 4 ++-- spec/models/notification_spec.rb | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/app/models/notification.rb b/app/models/notification.rb index 7e0e62683a..7cbab4dc8c 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -184,13 +184,13 @@ class Notification < ApplicationRecord return unless new_record? case activity_type - when 'Status', 'Follow', 'Favourite', 'FollowRequest', 'Poll', 'Report', 'AccountWarning' + when 'Status', 'Follow', 'Favourite', 'FollowRequest', 'Poll', 'Report' self.from_account_id = activity&.account_id when 'Mention' self.from_account_id = activity&.status&.account_id when 'Account' self.from_account_id = activity&.id - when 'AccountRelationshipSeveranceEvent' + when 'AccountRelationshipSeveranceEvent', 'AccountWarning' # These do not really have an originating account, but this is mandatory # in the data model, and the recipient's account will by definition # always exist diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 172d1c65b9..3c7d51ae1a 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -138,6 +138,17 @@ RSpec.describe Notification do expect(notification.account).to eq(account) end end + + context 'when activity_type is an AccountWarning' do + it 'sets the notification from_account to the recipient of the notification' do + account = Fabricate(:account) + account_warning = Fabricate(:account_warning, target_account: account) + + notification = Fabricate.build(:notification, activity_type: 'AccountWarning', activity: account_warning, account: account) + + expect(notification.from_account).to eq(account) + end + end end describe '.preload_cache_collection_target_statuses' do From 91ca90e25b2de95ef44dc149866b16df2663e205 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 26 Apr 2024 15:19:02 +0200 Subject: [PATCH 015/658] Fix Idempotency-Key ignored when scheduling a post (#30084) --- app/services/post_status_service.rb | 4 ++-- spec/services/post_status_service_spec.rb | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 8aa43ab245..22a6a24afd 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -160,7 +160,7 @@ class PostStatusService < BaseService def idempotency_duplicate if scheduled? - @account.schedule_statuses.find(@idempotency_duplicate) + @account.scheduled_statuses.find(@idempotency_duplicate) else @account.statuses.find(@idempotency_duplicate) end @@ -211,7 +211,7 @@ class PostStatusService < BaseService end def scheduled_options - @options.tap do |options_hash| + @options.dup.tap do |options_hash| options_hash[:in_reply_to_id] = options_hash.delete(:thread)&.id options_hash[:application_id] = options_hash.delete(:application)&.id options_hash[:scheduled_at] = nil diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index 3c2e4f3a79..18891bf118 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -54,6 +54,13 @@ RSpec.describe PostStatusService do .to not_change { account.statuses_count } .and(not_change { previous_status.replies_count }) end + + it 'returns existing status when used twice with idempotency key' do + account = Fabricate(:account) + status1 = subject.call(account, text: 'test', idempotency: 'meepmeep', scheduled_at: future) + status2 = subject.call(account, text: 'test', idempotency: 'meepmeep', scheduled_at: future) + expect(status2.id).to eq status1.id + end end it 'creates response to the original status of boost' do From ac82f34f7dd87a45860dd206e4244ae39c2d449e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Apr 2024 16:49:54 +0200 Subject: [PATCH 016/658] Update dependency pino to v9 (#30057) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- streaming/package.json | 2 +- yarn.lock | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/streaming/package.json b/streaming/package.json index f90a1e4404..a0e7d96bb5 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -24,7 +24,7 @@ "jsdom": "^24.0.0", "pg": "^8.5.0", "pg-connection-string": "^2.6.0", - "pino": "^8.17.2", + "pino": "^9.0.0", "pino-http": "^9.0.0", "prom-client": "^15.0.0", "uuid": "^9.0.0", diff --git a/yarn.lock b/yarn.lock index b9f1c3d4d5..c8a9476f25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2904,7 +2904,7 @@ __metadata: jsdom: "npm:^24.0.0" pg: "npm:^8.5.0" pg-connection-string: "npm:^2.6.0" - pino: "npm:^8.17.2" + pino: "npm:^9.0.0" pino-http: "npm:^9.0.0" pino-pretty: "npm:^11.0.0" prom-client: "npm:^15.0.0" @@ -12920,13 +12920,13 @@ __metadata: languageName: node linkType: hard -"pino-abstract-transport@npm:^1.0.0, pino-abstract-transport@npm:^1.1.0": - version: 1.1.0 - resolution: "pino-abstract-transport@npm:1.1.0" +"pino-abstract-transport@npm:^1.0.0, pino-abstract-transport@npm:^1.1.0, pino-abstract-transport@npm:^1.2.0": + version: 1.2.0 + resolution: "pino-abstract-transport@npm:1.2.0" dependencies: readable-stream: "npm:^4.0.0" split2: "npm:^4.0.0" - checksum: 10c0/6e9b9d5a2c0a37f91ecaf224d335daae1ae682b1c79a05b06ef9e0f0a5d289f8e597992217efc857796dae6f1067e9b4882f95c6228ff433ddc153532cae8aca + checksum: 10c0/b4ab59529b7a91f488440147fc58ee0827a6c1c5ca3627292339354b1381072c1a6bfa9b46d03ad27872589e8477ecf74da12cf286e1e6b665ac64a3b806bf07 languageName: node linkType: hard @@ -12973,7 +12973,7 @@ __metadata: languageName: node linkType: hard -"pino@npm:^8.17.1, pino@npm:^8.17.2": +"pino@npm:^8.17.1": version: 8.20.0 resolution: "pino@npm:8.20.0" dependencies: @@ -12994,6 +12994,27 @@ __metadata: languageName: node linkType: hard +"pino@npm:^9.0.0": + version: 9.0.0 + resolution: "pino@npm:9.0.0" + dependencies: + atomic-sleep: "npm:^1.0.0" + fast-redact: "npm:^3.1.1" + on-exit-leak-free: "npm:^2.1.0" + pino-abstract-transport: "npm:^1.2.0" + pino-std-serializers: "npm:^6.0.0" + process-warning: "npm:^3.0.0" + quick-format-unescaped: "npm:^4.0.3" + real-require: "npm:^0.2.0" + safe-stable-stringify: "npm:^2.3.1" + sonic-boom: "npm:^3.7.0" + thread-stream: "npm:^2.6.0" + bin: + pino: bin.js + checksum: 10c0/10ef10aee0cf80af8ed83468cff2e29d642b6794b53cf641e1abcaf9e9958d8bcbc6e09d62757054aef3b4415c45d66a5018da11d43b81a23ba299ef5dc4e8b1 + languageName: node + linkType: hard + "pirates@npm:^4.0.4": version: 4.0.6 resolution: "pirates@npm:4.0.6" @@ -16703,12 +16724,12 @@ __metadata: languageName: node linkType: hard -"thread-stream@npm:^2.0.0": - version: 2.4.1 - resolution: "thread-stream@npm:2.4.1" +"thread-stream@npm:^2.0.0, thread-stream@npm:^2.6.0": + version: 2.6.0 + resolution: "thread-stream@npm:2.6.0" dependencies: real-require: "npm:^0.2.0" - checksum: 10c0/ce29265810b9550ce896726301ff006ebfe96b90292728f07cfa4c379740585583046e2a8018afc53aca66b18fed12b33a84f3883e7ebc317185f6682898b8f8 + checksum: 10c0/276e2545b33273232eb2c22c53fc11844951c1322f8a78c522477af716ebcfe0d106ccf1fbc455f6e48d928e93231fed6377ce91fdcb3885086e8ffa1f011c88 languageName: node linkType: hard From b67b61b963df686ccdb9f69d8600090e3d88e5a3 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 26 Apr 2024 10:50:39 -0400 Subject: [PATCH 017/658] Ignore dotenv *.local files (#29932) --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2f94b751ab..a70f30f952 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,6 @@ yarn-debug.log # Ignore Docker option files docker-compose.override.yml + +# Ignore dotenv .local files +.env*.local From bb8c6346fbedc67b6ce447deb9cc2efa16fad70a Mon Sep 17 00:00:00 2001 From: Michael Stanclift Date: Fri, 26 Apr 2024 10:17:41 -0500 Subject: [PATCH 018/658] Reword and rearrange Content Retention page (#27733) --- .../admin/settings/content_retention/show.html.haml | 10 +++++++--- config/locales/en.yml | 1 + config/locales/simple_form.en.yml | 8 ++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/views/admin/settings/content_retention/show.html.haml b/app/views/admin/settings/content_retention/show.html.haml index 4b2ee572e3..57485c1108 100644 --- a/app/views/admin/settings/content_retention/show.html.haml +++ b/app/views/admin/settings/content_retention/show.html.haml @@ -14,14 +14,18 @@ = f.input :media_cache_retention_period, input_html: { pattern: '[0-9]+' }, wrapper: :with_block_label + = f.input :backups_retention_period, + input_html: { pattern: '[0-9]+' }, + wrapper: :with_block_label + + %h4= t('admin.settings.content_retention.danger_zone') + + .fields-group = f.input :content_cache_retention_period, hint: false, input_html: { pattern: '[0-9]+' }, warning_hint: t('simple_form.hints.form_admin_settings.content_cache_retention_period'), wrapper: :with_block_label - = f.input :backups_retention_period, - input_html: { pattern: '[0-9]+' }, - wrapper: :with_block_label .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/config/locales/en.yml b/config/locales/en.yml index 6cd996594d..446d06f0d1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -751,6 +751,7 @@ en: desc_html: This relies on external scripts from hCaptcha, which may be a security and privacy concern. In addition, this can make the registration process significantly less accessible to some (especially disabled) people. For these reasons, please consider alternative measures such as approval-based or invite-based registration. title: Require new users to solve a CAPTCHA to confirm their account content_retention: + danger_zone: Danger zone preamble: Control how user-generated content is stored in Mastodon. title: Content retention default_noindex: diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 4ba6e88f41..7304bdc22f 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -77,13 +77,13 @@ en: warn: Hide the filtered content behind a warning mentioning the filter's title form_admin_settings: activity_api_enabled: Counts of locally published posts, active users, and new registrations in weekly buckets - backups_retention_period: Keep generated user archives for the specified number of days. + backups_retention_period: Users have the ability to generate archives of their posts to download later. When set to a positive value, these archives will be automatically deleted from your storage after the specified number of days. bootstrap_timeline_accounts: These accounts will be pinned to the top of new users' follow recommendations. closed_registrations_message: Displayed when sign-ups are closed - content_cache_retention_period: All posts and boosts from other servers will be deleted after the specified number of days. Some posts may not be recoverable. All related bookmarks, favourites and boosts will also be lost and impossible to undo. + content_cache_retention_period: All posts from other servers (including boosts and replies) will be deleted after the specified number of days, without regard to any local user interaction with those posts. This includes posts where a local user has marked it as bookmarks or favorites. Private mentions between users from different instances will also be lost and impossible to restore. Use of this setting is intended for special purpose instances and breaks many user expectations when implemented for general purpose use. custom_css: You can apply custom styles on the web version of Mastodon. mascot: Overrides the illustration in the advanced web interface. - media_cache_retention_period: Downloaded media files will be deleted after the specified number of days when set to a positive value, and re-downloaded on demand. + media_cache_retention_period: Media files from posts made by remote users are cached on your server. When set to a positive value, media will be deleted after the specified number of days. If the media data is requested after it is deleted, it will be re-downloaded, if the source content is still available. Due to restrictions on how often link preview cards poll third-party sites, it is recommended to set this value to at least 14 days, or link preview cards will not be updated on demand before that time. peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense. profile_directory: The profile directory lists all users who have opted-in to be discoverable. require_invite_text: When sign-ups require manual approval, make the “Why do you want to join?” text input mandatory rather than optional @@ -243,7 +243,7 @@ en: backups_retention_period: User archive retention period bootstrap_timeline_accounts: Always recommend these accounts to new users closed_registrations_message: Custom message when sign-ups are not available - content_cache_retention_period: Content cache retention period + content_cache_retention_period: Remote content retention period custom_css: Custom CSS mascot: Custom mascot (legacy) media_cache_retention_period: Media cache retention period From 17e0a31fe3b1bdfd5f4fd950ea6641f23b2b3a99 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Apr 2024 17:32:38 +0200 Subject: [PATCH 019/658] Update dependency cssnano to v7 (#30061) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 324 +++++++++++++++++++++++++-------------------------- 2 files changed, 163 insertions(+), 163 deletions(-) diff --git a/package.json b/package.json index 787ca3600c..0b5c3484d2 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "core-js": "^3.30.2", "cross-env": "^7.0.3", "css-loader": "^5.2.7", - "cssnano": "^6.0.1", + "cssnano": "^7.0.0", "detect-passive-events": "^2.0.3", "emoji-mart": "npm:emoji-mart-lazyload@latest", "escape-html": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index c8a9476f25..0b60c39c91 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2787,7 +2787,7 @@ __metadata: core-js: "npm:^3.30.2" cross-env: "npm:^7.0.3" css-loader: "npm:^5.2.7" - cssnano: "npm:^6.0.1" + cssnano: "npm:^7.0.0" detect-passive-events: "npm:^2.0.3" emoji-mart: "npm:emoji-mart-lazyload@latest" escape-html: "npm:^1.0.3" @@ -6659,64 +6659,64 @@ __metadata: languageName: node linkType: hard -"cssnano-preset-default@npm:^6.1.2": - version: 6.1.2 - resolution: "cssnano-preset-default@npm:6.1.2" +"cssnano-preset-default@npm:^7.0.1": + version: 7.0.1 + resolution: "cssnano-preset-default@npm:7.0.1" dependencies: browserslist: "npm:^4.23.0" css-declaration-sorter: "npm:^7.2.0" - cssnano-utils: "npm:^4.0.2" - postcss-calc: "npm:^9.0.1" - postcss-colormin: "npm:^6.1.0" - postcss-convert-values: "npm:^6.1.0" - postcss-discard-comments: "npm:^6.0.2" - postcss-discard-duplicates: "npm:^6.0.3" - postcss-discard-empty: "npm:^6.0.3" - postcss-discard-overridden: "npm:^6.0.2" - postcss-merge-longhand: "npm:^6.0.5" - postcss-merge-rules: "npm:^6.1.1" - postcss-minify-font-values: "npm:^6.1.0" - postcss-minify-gradients: "npm:^6.0.3" - postcss-minify-params: "npm:^6.1.0" - postcss-minify-selectors: "npm:^6.0.4" - postcss-normalize-charset: "npm:^6.0.2" - postcss-normalize-display-values: "npm:^6.0.2" - postcss-normalize-positions: "npm:^6.0.2" - postcss-normalize-repeat-style: "npm:^6.0.2" - postcss-normalize-string: "npm:^6.0.2" - postcss-normalize-timing-functions: "npm:^6.0.2" - postcss-normalize-unicode: "npm:^6.1.0" - postcss-normalize-url: "npm:^6.0.2" - postcss-normalize-whitespace: "npm:^6.0.2" - postcss-ordered-values: "npm:^6.0.2" - postcss-reduce-initial: "npm:^6.1.0" - postcss-reduce-transforms: "npm:^6.0.2" - postcss-svgo: "npm:^6.0.3" - postcss-unique-selectors: "npm:^6.0.4" + cssnano-utils: "npm:^5.0.0" + postcss-calc: "npm:^10.0.0" + postcss-colormin: "npm:^7.0.0" + postcss-convert-values: "npm:^7.0.0" + postcss-discard-comments: "npm:^7.0.0" + postcss-discard-duplicates: "npm:^7.0.0" + postcss-discard-empty: "npm:^7.0.0" + postcss-discard-overridden: "npm:^7.0.0" + postcss-merge-longhand: "npm:^7.0.0" + postcss-merge-rules: "npm:^7.0.0" + postcss-minify-font-values: "npm:^7.0.0" + postcss-minify-gradients: "npm:^7.0.0" + postcss-minify-params: "npm:^7.0.0" + postcss-minify-selectors: "npm:^7.0.0" + postcss-normalize-charset: "npm:^7.0.0" + postcss-normalize-display-values: "npm:^7.0.0" + postcss-normalize-positions: "npm:^7.0.0" + postcss-normalize-repeat-style: "npm:^7.0.0" + postcss-normalize-string: "npm:^7.0.0" + postcss-normalize-timing-functions: "npm:^7.0.0" + postcss-normalize-unicode: "npm:^7.0.0" + postcss-normalize-url: "npm:^7.0.0" + postcss-normalize-whitespace: "npm:^7.0.0" + postcss-ordered-values: "npm:^7.0.0" + postcss-reduce-initial: "npm:^7.0.0" + postcss-reduce-transforms: "npm:^7.0.0" + postcss-svgo: "npm:^7.0.0" + postcss-unique-selectors: "npm:^7.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/af99021f936763850f5f35dc9e6a9dfb0da30856dea36e0420b011da2a447099471db2a5f3d1f5f52c0489da186caf9a439d8f048a80f82617077efb018333fa + checksum: 10c0/bee65239d25de2ba87e85b4091cbc1cac9ba1b57c9f803dff5a71ea8a55a885045805840dd732be284c28cca6343dece37fc76d7096aba37cfa02eff2ee7714c languageName: node linkType: hard -"cssnano-utils@npm:^4.0.2": - version: 4.0.2 - resolution: "cssnano-utils@npm:4.0.2" +"cssnano-utils@npm:^5.0.0": + version: 5.0.0 + resolution: "cssnano-utils@npm:5.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/260b8c8ffa48b908aa77ef129f9b8648ecd92aed405b20e7fe6b8370779dd603530344fc9d96683d53533246e48b36ac9d2aa5a476b4f81c547bbad86d187f35 + checksum: 10c0/492593fb45151e8622357bb958d0d80475372de38523ef0587d77e9c5f386beb55c30b41f2f3c735a374a230bc61404eb7ae9c2beeab0666afb499442c62ecba languageName: node linkType: hard -"cssnano@npm:^6.0.1": - version: 6.1.2 - resolution: "cssnano@npm:6.1.2" +"cssnano@npm:^7.0.0": + version: 7.0.1 + resolution: "cssnano@npm:7.0.1" dependencies: - cssnano-preset-default: "npm:^6.1.2" + cssnano-preset-default: "npm:^7.0.1" lilconfig: "npm:^3.1.1" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/4df0dc0389b34b38acb09b7cfb07267b0eda95349c6d5e9b7666acc7200bb33359650869a60168e9d878298b05f4ad2c7f070815c90551720a3f4e1037f79691 + checksum: 10c0/8b17d13efe98ec2db2fbde9ca24e91842b9afe2f80becc5e4271ee1170d77cf73eed3cdc2f35ed51bacdeac763ff85db45ae8e9627a8862bf01d457a819a640e languageName: node linkType: hard @@ -13076,15 +13076,15 @@ __metadata: languageName: node linkType: hard -"postcss-calc@npm:^9.0.1": - version: 9.0.1 - resolution: "postcss-calc@npm:9.0.1" +"postcss-calc@npm:^10.0.0": + version: 10.0.0 + resolution: "postcss-calc@npm:10.0.0" dependencies: - postcss-selector-parser: "npm:^6.0.11" + postcss-selector-parser: "npm:^6.0.16" postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.2 - checksum: 10c0/e0df07337162dbcaac5d6e030c7fd289e21da8766a9daca5d6b2b3c8094bb524ae5d74c70048ea7fe5fe4960ce048c60ac97922d917c3bbff34f58e9d2b0eb0e + postcss: ^8.4.38 + checksum: 10c0/d4d529f2f71b49f17441eed74a7564ccd2779c72ed8648d4bb2530261a27c0ca01fe6a07260e7bf57e55f46dd68dea07e52fd1a6b538db7bc13015124be258a5 languageName: node linkType: hard @@ -13138,9 +13138,9 @@ __metadata: languageName: node linkType: hard -"postcss-colormin@npm:^6.1.0": - version: 6.1.0 - resolution: "postcss-colormin@npm:6.1.0" +"postcss-colormin@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-colormin@npm:7.0.0" dependencies: browserslist: "npm:^4.23.0" caniuse-api: "npm:^3.0.0" @@ -13148,19 +13148,19 @@ __metadata: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/0802963fa0d8f2fe408b2e088117670f5303c69a58c135f0ecf0e5ceff69e95e87111b22c4e29c9adb2f69aa8d3bc175f4e8e8708eeb99c9ffc36c17064de427 + checksum: 10c0/d365a5365e0a94748309d32c7208cd06249bc53eb82cc32c771de4073b109fa8552e58d60dbe84d7e69e68081ed8a01fbf645d38a650e90cb2e13b21043cd796 languageName: node linkType: hard -"postcss-convert-values@npm:^6.1.0": - version: 6.1.0 - resolution: "postcss-convert-values@npm:6.1.0" +"postcss-convert-values@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-convert-values@npm:7.0.0" dependencies: browserslist: "npm:^4.23.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/a80066965cb58fe8fcaf79f306b32c83fc678e1f0678e43f4db3e9fee06eed6db92cf30631ad348a17492769d44757400493c91a33ee865ee8dedea9234a11f5 + checksum: 10c0/5d7cfa06f307e024574a1842016f006691e0c1932352f53a99ce8f2f9930c64c3c1ae17518e9e4e5176630b99f1beaab37bc339bc779fb07dc543670ae66bb21 languageName: node linkType: hard @@ -13218,39 +13218,39 @@ __metadata: languageName: node linkType: hard -"postcss-discard-comments@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-discard-comments@npm:6.0.2" +"postcss-discard-comments@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-discard-comments@npm:7.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/338a1fcba7e2314d956e5e5b9bd1e12e6541991bf85ac72aed6e229a029bf60edb31f11576b677623576169aa7d9c75e1be259ac7b50d0b735b841b5518f9da9 + checksum: 10c0/7fef7deea85c1e68161f69057be19a3aedd54d23c9b464c9b1531faa7a115f0c96a4f0ee3a560ce300578599dbc8114fe0fb744208b20b9d2fd8df1b4b39c58a languageName: node linkType: hard -"postcss-discard-duplicates@npm:^6.0.3": - version: 6.0.3 - resolution: "postcss-discard-duplicates@npm:6.0.3" +"postcss-discard-duplicates@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-discard-duplicates@npm:7.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/24d2f00e54668f2837eb38a64b1751d7a4a73b2752f9749e61eb728f1fae837984bc2b339f7f5207aff5f66f72551253489114b59b9ba21782072677a81d7d1b + checksum: 10c0/37d568dc18d47b8b9f0fd6d5115b1faf96c2bf429fc4586508a773533479e18627d6260cad6a3ca7d3bfc2f220fd9448410aee40e07f2ec6c6f96bbe3595dbc8 languageName: node linkType: hard -"postcss-discard-empty@npm:^6.0.3": - version: 6.0.3 - resolution: "postcss-discard-empty@npm:6.0.3" +"postcss-discard-empty@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-discard-empty@npm:7.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/1af08bb29f18eda41edf3602b257d89a4cf0a16f79fc773cfebd4a37251f8dbd9b77ac18efe55d0677d000b43a8adf2ef9328d31961c810e9433a38494a1fa65 + checksum: 10c0/b54fc9ad59a6015f6b82b8c826717a4a2f82b272608f6ae37a0b568f4f6c503f5ac7d13d415853a946a0422cb37b9fe1d5ddcee91fe0c2086001138710600d8b languageName: node linkType: hard -"postcss-discard-overridden@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-discard-overridden@npm:6.0.2" +"postcss-discard-overridden@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-discard-overridden@npm:7.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/fda70ef3cd4cb508369c5bbbae44d7760c40ec9f2e65df1cd1b6e0314317fb1d25ae7f64987ca84e66889c1e9d1862487a6ce391c159dfe04d536597bfc5030d + checksum: 10c0/ca00ed1d4e8793fc780039f235fa2caef123d3aa28cae47cc1472ca03b21386c39fae1f11fbf319dcb94c6bda923824067254c7e20e8b00354b47015dc754658 languageName: node linkType: hard @@ -13368,77 +13368,77 @@ __metadata: languageName: node linkType: hard -"postcss-merge-longhand@npm:^6.0.5": - version: 6.0.5 - resolution: "postcss-merge-longhand@npm:6.0.5" +"postcss-merge-longhand@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-merge-longhand@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" - stylehacks: "npm:^6.1.1" + stylehacks: "npm:^7.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/5a223a7f698c05ab42e9997108a7ff27ea1e0c33a11a353d65a04fc89c3b5b750b9e749550d76b6406329117a055adfc79dde7fee48dca5c8e167a2854ae3fea + checksum: 10c0/5f814f396a5107dcb5e74c2d4e55ebcd03b9bc2b3619ed7aea63a441854023ce349bc371d30aec1ac33a375139afac02709e7721e055b5e624701ac6576e8a10 languageName: node linkType: hard -"postcss-merge-rules@npm:^6.1.1": - version: 6.1.1 - resolution: "postcss-merge-rules@npm:6.1.1" +"postcss-merge-rules@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-merge-rules@npm:7.0.0" dependencies: browserslist: "npm:^4.23.0" caniuse-api: "npm:^3.0.0" - cssnano-utils: "npm:^4.0.2" + cssnano-utils: "npm:^5.0.0" postcss-selector-parser: "npm:^6.0.16" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/6d8952dbb19b1e59bf5affe0871fa1be6515103466857cff5af879d6cf619659f8642ec7a931cabb7cdbd393d8c1e91748bf70bee70fa3edea010d4e25786d04 + checksum: 10c0/d9cb3a4e55db57aa7ba0bb1caefb82db93c8493d2b3db66091dae9d5794ca04729e660115765ff254d0eb960e4db037f6c5b92562b396b05216888d12acc08e0 languageName: node linkType: hard -"postcss-minify-font-values@npm:^6.1.0": - version: 6.1.0 - resolution: "postcss-minify-font-values@npm:6.1.0" +"postcss-minify-font-values@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-minify-font-values@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/0d6567170c22a7db42096b5eac298f041614890fbe01759a9fa5ccda432f2bb09efd399d92c11bf6675ae13ccd259db4602fad3c358317dee421df5f7ab0a003 + checksum: 10c0/f8be40099a6986d96b9cd2eb9c32a9c681efc6ecd6504c9ab7e01feb9e688c8b9656dfd7f35aa6de2585a86d607f62152ee81d0175e712e4658d184d25f63d58 languageName: node linkType: hard -"postcss-minify-gradients@npm:^6.0.3": - version: 6.0.3 - resolution: "postcss-minify-gradients@npm:6.0.3" +"postcss-minify-gradients@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-minify-gradients@npm:7.0.0" dependencies: colord: "npm:^2.9.3" - cssnano-utils: "npm:^4.0.2" + cssnano-utils: "npm:^5.0.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/7fcbcec94fe5455b89fe1b424a451198e60e0407c894bbacdc062d9fdef2f8571b483b5c3bb17f22d2f1249431251b2de22e1e4e8b0614d10624f8ee6e71afd2 + checksum: 10c0/15d162192b598242e14def81a62e30cf273ab14f1db702c391e6bdd442c570a1aa76fc326874253a2d67f75b4d4fe73ba4f664e85dbff883f24b7090c340bfad languageName: node linkType: hard -"postcss-minify-params@npm:^6.1.0": - version: 6.1.0 - resolution: "postcss-minify-params@npm:6.1.0" +"postcss-minify-params@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-minify-params@npm:7.0.0" dependencies: browserslist: "npm:^4.23.0" - cssnano-utils: "npm:^4.0.2" + cssnano-utils: "npm:^5.0.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/e5c38c3e5fb42e2ca165764f983716e57d854a63a477f7389ccc94cd2ab8123707006613bd7f29acc6eafd296fff513aa6d869c98ac52590f886d641cb21a59e + checksum: 10c0/28a7ae313a197aeaff8b3fa1e695a6443b11a74258374a05adee6a1b05f5849ef52037b7a5069d6910614b03b4610acdaf4a76f38b89cb42e813a8cb5ec2fc01 languageName: node linkType: hard -"postcss-minify-selectors@npm:^6.0.4": - version: 6.0.4 - resolution: "postcss-minify-selectors@npm:6.0.4" +"postcss-minify-selectors@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-minify-selectors@npm:7.0.0" dependencies: postcss-selector-parser: "npm:^6.0.16" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/695ec2e1e3a7812b0cabe1105d0ed491760be3d8e9433914fb5af1fc30a84e6dc24089cd31b7e300de620b8e7adf806526c1acf8dd14077a7d1d2820c60a327c + checksum: 10c0/6baf0ea71b8dfd01bdb5b516d01aa00244c55cad8d9c674358d735cef2a6aca6586dd480d419cc8d3f470e6d2d7d19354592044f19766993caf9800d3d7e0d36 languageName: node linkType: hard @@ -13499,101 +13499,101 @@ __metadata: languageName: node linkType: hard -"postcss-normalize-charset@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-normalize-charset@npm:6.0.2" +"postcss-normalize-charset@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-charset@npm:7.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/af32a3b4cf94163d728b8aa935b2494c9f69fbc96a33b35f67ae15dbdef7fcc8732569df97cbaaf20ca6c0103c39adad0cfce2ba07ffed283796787f6c36f410 + checksum: 10c0/06d9c4487a4b0e195133a1fb7a115db7014e49d2567cce73e24c59f473f0e65a1999850a726afb3bdb2d36017a3e5c92ac4fd2a7ecc427da4ff79522765fabdd languageName: node linkType: hard -"postcss-normalize-display-values@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-normalize-display-values@npm:6.0.2" +"postcss-normalize-display-values@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-display-values@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/782761850c7e697fdb6c3ff53076de716a71b60f9e835efb2f7ef238de347c88b5d55f0d43cf5c608e1ee58de65360e3d9fccd5f20774bba08ded7c87d8a5651 + checksum: 10c0/439524e1d3ed36d6265c05da10540e17aa8605e1b396f71ca4364ab3b8b98ca97763c58c211fb9492662429d43613a7fe7009a8638c84a8db327e572c382272a languageName: node linkType: hard -"postcss-normalize-positions@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-normalize-positions@npm:6.0.2" +"postcss-normalize-positions@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-positions@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/9fdd42a47226bbda5f68774f3c4c3a90eb4fa708aef5a997c6a52fe6cac06585c9774038fe3bc1aa86a203c29223b8d8db6ebe7580c1aa293154f2b48db0b038 + checksum: 10c0/428763c937cd178c8ee544cd93a9d1fef667dc9a8700ffe2e61b0beeea7f64f712492b9aeb8a1ef927ab752ec34be7ddeb23d2b50e4bc6eba02b0e58312b27a7 languageName: node linkType: hard -"postcss-normalize-repeat-style@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-normalize-repeat-style@npm:6.0.2" +"postcss-normalize-repeat-style@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-repeat-style@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/9133ccbdf1286920c1cd0d01c1c5fa0bd3251b717f2f3e47d691dcc44978ac1dc419d20d9ae5428bd48ee542059e66b823ba699356f5968ccced5606c7c7ca34 + checksum: 10c0/cf7cd9f355fd26f1c9b0c11a923029ac5ea3020520db5a9778dd19c5ee1f48a1f1f368b4ae75fc6b63cb5761eef72333e486ab0de1537b9cb62d213a8c5576d0 languageName: node linkType: hard -"postcss-normalize-string@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-normalize-string@npm:6.0.2" +"postcss-normalize-string@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-string@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/fecc2d52c4029b24fecf2ca2fb45df5dbdf9f35012194ad4ea80bc7be3252cdcb21a0976400902320595aa6178f2cc625cc804c6b6740aef6efa42105973a205 + checksum: 10c0/8857563f85841ce432bb9a5a9ba129847890b61693adff96d565b69dc2d5456f54dec33f4f6ce5b0abf0a484dbfb0145846d99f988959c5ac875a86a2a180576 languageName: node linkType: hard -"postcss-normalize-timing-functions@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-normalize-timing-functions@npm:6.0.2" +"postcss-normalize-timing-functions@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-timing-functions@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/a22af0b3374704e59ae70bbbcc66b7029137e284f04e30a2ad548818d1540d6c1ed748dd8f689b9b6df5c1064085a00ad07b6f7e25ffaad49d4e661b616cdeae + checksum: 10c0/bc5f6999b4c9e28e5be785ef90fe68fd48d44059ecc73ee194c2603260597d685b13a1e1751df9a2cee100fea7abb7e1b1cbcf1a7a428a576961705c9d426788 languageName: node linkType: hard -"postcss-normalize-unicode@npm:^6.1.0": - version: 6.1.0 - resolution: "postcss-normalize-unicode@npm:6.1.0" +"postcss-normalize-unicode@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-unicode@npm:7.0.0" dependencies: browserslist: "npm:^4.23.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/ff5746670d94dd97b49a0955c3c71ff516fb4f54bbae257f877d179bacc44a62e50a0fd6e7ddf959f2ca35c335de4266b0c275d880bb57ad7827189339ab1582 + checksum: 10c0/f2d6ab0076c006dcf3ed33ba30686f2d29e81a408c66acced22e2c942df6d613697ea786137833dd258aafab5fda4d3eb27df13a82df830357dbad9b79154881 languageName: node linkType: hard -"postcss-normalize-url@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-normalize-url@npm:6.0.2" +"postcss-normalize-url@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-url@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/4718f1c0657788d2c560b340ee8e0a4eb3eb053eba6fbbf489e9a6e739b4c5f9ce1957f54bd03497c50a1f39962bf6ab9ff6ba4976b69dd160f6afd1670d69b7 + checksum: 10c0/3050e228be48fe0121d1316c267e629b232e8401a547128d142c3dea55eeae1e232c9beeea5c76439009188993b14925c5cf40e3a44856d076a7b8fcf4721f86 languageName: node linkType: hard -"postcss-normalize-whitespace@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-normalize-whitespace@npm:6.0.2" +"postcss-normalize-whitespace@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-normalize-whitespace@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/d5275a88e29a894aeb83a2a833e816d2456dbf3f39961628df596ce205dcc4895186a023812ff691945e0804241ccc53e520d16591b5812288474b474bbaf652 + checksum: 10c0/8d61234962a4850fc61292592171e1d13de2e90d96a2eaed8c85672a05caceda02a3bd1cb495cb72414741f99d50083362df14923efaca1b3e09657d24cea34b languageName: node linkType: hard @@ -13606,15 +13606,15 @@ __metadata: languageName: node linkType: hard -"postcss-ordered-values@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-ordered-values@npm:6.0.2" +"postcss-ordered-values@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-ordered-values@npm:7.0.0" dependencies: - cssnano-utils: "npm:^4.0.2" + cssnano-utils: "npm:^5.0.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/aece23a289228aa804217a85f8da198d22b9123f02ca1310b81834af380d6fbe115e4300683599b4a2ab7f1c6a1dbd6789724c47c38e2b0a3774f2ea4b4f0963 + checksum: 10c0/42b14f9518b573318594c2aeb2f13fd1fbe44936d14f1b28a438e7a82644ace9a2946699bebfe7a2d383534dc24e7203c35308d749f3c585a86daa238ad920a4 languageName: node linkType: hard @@ -13730,26 +13730,26 @@ __metadata: languageName: node linkType: hard -"postcss-reduce-initial@npm:^6.1.0": - version: 6.1.0 - resolution: "postcss-reduce-initial@npm:6.1.0" +"postcss-reduce-initial@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-reduce-initial@npm:7.0.0" dependencies: browserslist: "npm:^4.23.0" caniuse-api: "npm:^3.0.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/a8f28cf51ce9a1b9423cce1a01c1d7cbee90125930ec36435a0073e73aef402d90affe2fd3600c964b679cf738869fda447b95a9acce74414e9d67d5c6ba8646 + checksum: 10c0/ed50cd680ce258df953b82ce9b3fb52564d08548724577810800e236d017d80430cbccb4b1ad38b0f4d521663598e44ab93136b20064231181ef49e1e113ae10 languageName: node linkType: hard -"postcss-reduce-transforms@npm:^6.0.2": - version: 6.0.2 - resolution: "postcss-reduce-transforms@npm:6.0.2" +"postcss-reduce-transforms@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-reduce-transforms@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/755ef27b3d083f586ac831f0c611a66e76f504d27e2100dc7674f6b86afad597901b4520cb889fe58ca70e852aa7fd0c0acb69a63d39dfe6a95860b472394e7c + checksum: 10c0/b2d4b65e71d38b604b41937850d1d64794964d6eced90f05891cfae8a78c7a9fed49911f51da9dcc5d715ac18e8bc7eacf691f2c5321dfe4d781f3e4442dfea9 languageName: node linkType: hard @@ -13798,7 +13798,7 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4": +"postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4": version: 6.0.16 resolution: "postcss-selector-parser@npm:6.0.16" dependencies: @@ -13808,26 +13808,26 @@ __metadata: languageName: node linkType: hard -"postcss-svgo@npm:^6.0.3": - version: 6.0.3 - resolution: "postcss-svgo@npm:6.0.3" +"postcss-svgo@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-svgo@npm:7.0.0" dependencies: postcss-value-parser: "npm:^4.2.0" svgo: "npm:^3.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/994b15a88cbb411f32cfa98957faa5623c76f2d75fede51f5f47238f06b367ebe59c204fecbdaf21ccb9e727239a4b290087e04c502392658a0c881ddfbd61f2 + checksum: 10c0/0e724069b5de83aa2b8f8a4746cb60cb663e0a8bbab0e4ba995649cb0562205af57d1f54b89fb90d8ae04a4b7ac3ac6e3751afffc3cff697cb19f7a36b71b195 languageName: node linkType: hard -"postcss-unique-selectors@npm:^6.0.4": - version: 6.0.4 - resolution: "postcss-unique-selectors@npm:6.0.4" +"postcss-unique-selectors@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-unique-selectors@npm:7.0.0" dependencies: postcss-selector-parser: "npm:^6.0.16" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/bfb99d8a7c675c93f2e65c9d9d563477bfd46fdce9e2727d42d57982b31ccbaaf944e8034bfbefe48b3119e77fba7eb1b181c19b91cb3a5448058fa66a7c9ae9 + checksum: 10c0/33b532ad0e9271c5a379859e18adfdc72986bb538672cc0fbc06295d824f82dba3f7b57264e18a3214901bc5244ff5408d28b530374d24a088507287c7f520ce languageName: node linkType: hard @@ -16319,15 +16319,15 @@ __metadata: languageName: node linkType: hard -"stylehacks@npm:^6.1.1": - version: 6.1.1 - resolution: "stylehacks@npm:6.1.1" +"stylehacks@npm:^7.0.0": + version: 7.0.0 + resolution: "stylehacks@npm:7.0.0" dependencies: browserslist: "npm:^4.23.0" postcss-selector-parser: "npm:^6.0.16" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/2dd2bccfd8311ff71492e63a7b8b86c3d7b1fff55d4ba5a2357aff97743e633d351cdc2f5ae3c0057637d00dab4ef5fc5b218a1b370e4585a41df22b5a5128be + checksum: 10c0/c1c0231974ab7922af3a535a9cb78bfe84997767da7defe111cc76d7f10c9e139fe8cb0f9d5bea87b0c0cc0166c82a6ec98a3d6242d7e29ef90adceecfd330ae languageName: node linkType: hard From 0cf6cf457d478427900299dffd009a9bfafeeb13 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Apr 2024 17:32:48 +0200 Subject: [PATCH 020/658] Update dependency selenium-webdriver to v4.20.1 (#30060) 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 7068f5dd55..620da84992 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -693,7 +693,7 @@ GEM scenic (1.8.0) activerecord (>= 4.0.0) railties (>= 4.0.0) - selenium-webdriver (4.19.0) + selenium-webdriver (4.20.1) base64 (~> 0.2) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) From de4a7bf53159f72a9a122bf8df21e8d5f4ad7512 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 26 Apr 2024 17:33:15 +0200 Subject: [PATCH 021/658] Change moderation warning notification icon (#30081) --- .../features/notifications/components/moderation_warning.tsx | 4 ++-- app/javascript/material-icons/400-24px/gavel-fill.svg | 1 + app/javascript/material-icons/400-24px/gavel.svg | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 app/javascript/material-icons/400-24px/gavel-fill.svg create mode 100644 app/javascript/material-icons/400-24px/gavel.svg diff --git a/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx b/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx index 02ae9b371e..2c1683e218 100644 --- a/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx +++ b/app/javascript/mastodon/features/notifications/components/moderation_warning.tsx @@ -1,6 +1,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import WarningIcon from '@/material-icons/400-24px/warning-fill.svg?react'; +import GavelIcon from '@/material-icons/400-24px/gavel.svg?react'; import { Icon } from 'mastodon/components/icon'; // This needs to be kept in sync with app/models/account_warning.rb @@ -62,7 +62,7 @@ export const ModerationWarning: React.FC = ({ action, id, hidden }) => { rel='noopener noreferrer' className='notification__moderation-warning' > - +

{intl.formatMessage(messages[action])}

diff --git a/app/javascript/material-icons/400-24px/gavel-fill.svg b/app/javascript/material-icons/400-24px/gavel-fill.svg new file mode 100644 index 0000000000..9699b8480a --- /dev/null +++ b/app/javascript/material-icons/400-24px/gavel-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/gavel.svg b/app/javascript/material-icons/400-24px/gavel.svg new file mode 100644 index 0000000000..9699b8480a --- /dev/null +++ b/app/javascript/material-icons/400-24px/gavel.svg @@ -0,0 +1 @@ + \ No newline at end of file From 65093c619fdd1b18a4cf0c288051d8c524d5f434 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 26 Apr 2024 19:11:27 +0200 Subject: [PATCH 022/658] Fix marker thunks to not ignore eslint directives for the whole file (#30089) --- app/javascript/mastodon/actions/markers.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/actions/markers.ts b/app/javascript/mastodon/actions/markers.ts index 84e5b33bcc..6ecc867169 100644 --- a/app/javascript/mastodon/actions/markers.ts +++ b/app/javascript/mastodon/actions/markers.ts @@ -3,7 +3,7 @@ import { List as ImmutableList } from 'immutable'; import { debounce } from 'lodash'; import type { MarkerJSON } from 'mastodon/api_types/markers'; -import type { RootState } from 'mastodon/store'; +import type { AppDispatch, RootState } from 'mastodon/store'; import { createAppAsyncThunk } from 'mastodon/store/typed_functions'; import api, { authorizationTokenFromState } from '../api'; @@ -72,18 +72,21 @@ interface MarkerParam { } function getLastHomeId(state: RootState): string | undefined { - /* eslint-disable @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return ( + // eslint-disable-next-line @typescript-eslint/no-unsafe-call state // @ts-expect-error state.timelines is not yet typed .getIn(['timelines', 'home', 'items'], ImmutableList()) // @ts-expect-error state.timelines is not yet typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access .find((item) => item !== null) ); } function getLastNotificationId(state: RootState): string | undefined { // @ts-expect-error state.notifications is not yet typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call return state.getIn(['notifications', 'lastReadId']); } @@ -131,8 +134,8 @@ export const submitMarkersAction = createAppAsyncThunk<{ }); const debouncedSubmitMarkers = debounce( - (dispatch) => { - dispatch(submitMarkersAction()); + (dispatch: AppDispatch) => { + void dispatch(submitMarkersAction()); }, 300000, { From 7201f99cf83a74331febd1624ca9aaace68af5e6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 03:41:59 -0400 Subject: [PATCH 023/658] Change default ruby version to 3.3.1 (#28013) --- .github/workflows/test-ruby.yml | 6 +++--- .ruby-version | 2 +- Dockerfile | 6 +++--- Gemfile.lock | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 3a78f8b43d..b28f5261c2 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -115,8 +115,8 @@ jobs: matrix: ruby-version: - '3.1' + - '3.2' - '.ruby-version' - - '3.3' steps: - uses: actions/checkout@v4 @@ -190,8 +190,8 @@ jobs: matrix: ruby-version: - '3.1' + - '3.2' - '.ruby-version' - - '3.3' steps: - uses: actions/checkout@v4 @@ -289,8 +289,8 @@ jobs: matrix: ruby-version: - '3.1' + - '3.2' - '.ruby-version' - - '3.3' search-image: - docker.elastic.co/elasticsearch/elasticsearch:7.17.13 include: diff --git a/.ruby-version b/.ruby-version index 351227fca3..bea438e9ad 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.4 +3.3.1 diff --git a/Dockerfile b/Dockerfile index a95d41a65b..4278242bc9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,15 +7,15 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} -# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.4"] -ARG RUBY_VERSION="3.2.4" +# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.1"] +ARG RUBY_VERSION="3.3.1" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] ARG NODE_MAJOR_VERSION="20" # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] ARG DEBIAN_VERSION="bookworm" # Node image to use for base image based on combined variables (ex: 20-bookworm-slim) FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node -# Ruby image to use for base image based on combined variables (ex: 3.2.4-slim-bookworm) +# Ruby image to use for base image based on combined variables (ex: 3.3.1-slim-bookworm) FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA diff --git a/Gemfile.lock b/Gemfile.lock index 620da84992..18564ea68b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -952,7 +952,7 @@ DEPENDENCIES xorcist (~> 1.1) RUBY VERSION - ruby 3.2.3p157 + ruby 3.3.1p55 BUNDLED WITH 2.5.9 From 4f4b77920eeb3ba65346862d489945494dfeab64 Mon Sep 17 00:00:00 2001 From: David Beck Date: Mon, 29 Apr 2024 00:55:58 -0700 Subject: [PATCH 024/658] Remove home marker updates (#22721) --- app/javascript/mastodon/actions/markers.ts | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/app/javascript/mastodon/actions/markers.ts b/app/javascript/mastodon/actions/markers.ts index 6ecc867169..91f78ee286 100644 --- a/app/javascript/mastodon/actions/markers.ts +++ b/app/javascript/mastodon/actions/markers.ts @@ -1,5 +1,3 @@ -import { List as ImmutableList } from 'immutable'; - import { debounce } from 'lodash'; import type { MarkerJSON } from 'mastodon/api_types/markers'; @@ -71,19 +69,6 @@ interface MarkerParam { last_read_id?: string; } -function getLastHomeId(state: RootState): string | undefined { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return ( - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - state - // @ts-expect-error state.timelines is not yet typed - .getIn(['timelines', 'home', 'items'], ImmutableList()) - // @ts-expect-error state.timelines is not yet typed - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - .find((item) => item !== null) - ); -} - function getLastNotificationId(state: RootState): string | undefined { // @ts-expect-error state.notifications is not yet typed // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call @@ -93,15 +78,8 @@ function getLastNotificationId(state: RootState): string | undefined { const buildPostMarkersParams = (state: RootState) => { const params = {} as { home?: MarkerParam; notifications?: MarkerParam }; - const lastHomeId = getLastHomeId(state); const lastNotificationId = getLastNotificationId(state); - if (lastHomeId && compareId(lastHomeId, state.markers.home) > 0) { - params.home = { - last_read_id: lastHomeId, - }; - } - if ( lastNotificationId && compareId(lastNotificationId, state.markers.notifications) > 0 From 36909065b544d06e8487f1e0679e595fd01a7f22 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 29 Apr 2024 10:02:41 +0200 Subject: [PATCH 025/658] Convert easy entrypoints files to Typescript (#30102) --- .../{application.js => application.ts} | 4 ++-- .../entrypoints/{error.js => error.ts} | 6 +++++- .../entrypoints/{inert.js => inert.ts} | 0 .../entrypoints/{mailer.js => mailer.ts} | 0 .../{public-path.js => public-path.ts} | 10 ++++++---- .../entrypoints/{share.jsx => share.tsx} | 16 ++++++++++------ package.json | 1 + yarn.lock | 8 ++++++++ 8 files changed, 32 insertions(+), 13 deletions(-) rename app/javascript/entrypoints/{application.js => application.ts} (81%) rename app/javascript/entrypoints/{error.js => error.ts} (64%) rename app/javascript/entrypoints/{inert.js => inert.ts} (100%) rename app/javascript/entrypoints/{mailer.js => mailer.ts} (100%) rename app/javascript/entrypoints/{public-path.js => public-path.ts} (69%) rename app/javascript/entrypoints/{share.jsx => share.tsx} (64%) diff --git a/app/javascript/entrypoints/application.js b/app/javascript/entrypoints/application.ts similarity index 81% rename from app/javascript/entrypoints/application.js rename to app/javascript/entrypoints/application.ts index d13388b479..1087b1c4cb 100644 --- a/app/javascript/entrypoints/application.js +++ b/app/javascript/entrypoints/application.ts @@ -1,5 +1,5 @@ import './public-path'; -import main from "mastodon/main"; +import main from 'mastodon/main'; import { start } from '../mastodon/common'; import { loadLocale } from '../mastodon/locales'; @@ -10,6 +10,6 @@ start(); loadPolyfills() .then(loadLocale) .then(main) - .catch(e => { + .catch((e: unknown) => { console.error(e); }); diff --git a/app/javascript/entrypoints/error.js b/app/javascript/entrypoints/error.ts similarity index 64% rename from app/javascript/entrypoints/error.js rename to app/javascript/entrypoints/error.ts index 6376dc2f5d..db68484f3a 100644 --- a/app/javascript/entrypoints/error.js +++ b/app/javascript/entrypoints/error.ts @@ -2,7 +2,9 @@ import './public-path'; import ready from '../mastodon/ready'; ready(() => { - const image = document.querySelector('img'); + const image = document.querySelector('img'); + + if (!image) return; image.addEventListener('mouseenter', () => { image.src = '/oops.gif'; @@ -11,4 +13,6 @@ ready(() => { image.addEventListener('mouseleave', () => { image.src = '/oops.png'; }); +}).catch((e: unknown) => { + console.error(e); }); diff --git a/app/javascript/entrypoints/inert.js b/app/javascript/entrypoints/inert.ts similarity index 100% rename from app/javascript/entrypoints/inert.js rename to app/javascript/entrypoints/inert.ts diff --git a/app/javascript/entrypoints/mailer.js b/app/javascript/entrypoints/mailer.ts similarity index 100% rename from app/javascript/entrypoints/mailer.js rename to app/javascript/entrypoints/mailer.ts diff --git a/app/javascript/entrypoints/public-path.js b/app/javascript/entrypoints/public-path.ts similarity index 69% rename from app/javascript/entrypoints/public-path.js rename to app/javascript/entrypoints/public-path.ts index f4d166a771..ac4b9355b9 100644 --- a/app/javascript/entrypoints/public-path.js +++ b/app/javascript/entrypoints/public-path.ts @@ -2,7 +2,7 @@ // to share the same assets regardless of instance configuration. // See https://webpack.js.org/guides/public-path/#on-the-fly -function removeOuterSlashes(string) { +function removeOuterSlashes(string: string) { return string.replace(/^\/*/, '').replace(/\/*$/, ''); } @@ -15,7 +15,9 @@ function formatPublicPath(host = '', path = '') { return `${formattedHost}/${formattedPath}/`; } -const cdnHost = document.querySelector('meta[name=cdn-host]'); +const cdnHost = document.querySelector('meta[name=cdn-host]'); -// eslint-disable-next-line no-undef -__webpack_public_path__ = formatPublicPath(cdnHost ? cdnHost.content : '', process.env.PUBLIC_OUTPUT_PATH); +__webpack_public_path__ = formatPublicPath( + cdnHost ? cdnHost.content : '', + process.env.PUBLIC_OUTPUT_PATH, +); diff --git a/app/javascript/entrypoints/share.jsx b/app/javascript/entrypoints/share.tsx similarity index 64% rename from app/javascript/entrypoints/share.jsx rename to app/javascript/entrypoints/share.tsx index 7b5723091c..7926250851 100644 --- a/app/javascript/entrypoints/share.jsx +++ b/app/javascript/entrypoints/share.tsx @@ -2,7 +2,7 @@ import './public-path'; import { createRoot } from 'react-dom/client'; import { start } from '../mastodon/common'; -import ComposeContainer from '../mastodon/containers/compose_container'; +import ComposeContainer from '../mastodon/containers/compose_container'; import { loadPolyfills } from '../mastodon/polyfills'; import ready from '../mastodon/ready'; @@ -16,7 +16,7 @@ function loaded() { if (!attr) return; - const props = JSON.parse(attr); + const props = JSON.parse(attr) as object; const root = createRoot(mountNode); root.render(); @@ -24,9 +24,13 @@ function loaded() { } function main() { - ready(loaded); + ready(loaded).catch((error: unknown) => { + console.error(error); + }); } -loadPolyfills().then(main).catch(error => { - console.error(error); -}); +loadPolyfills() + .then(main) + .catch((error: unknown) => { + console.error(error); + }); diff --git a/package.json b/package.json index 0b5c3484d2..24d81ea476 100644 --- a/package.json +++ b/package.json @@ -167,6 +167,7 @@ "@types/redux-immutable": "^4.0.3", "@types/requestidlecallback": "^0.3.5", "@types/webpack": "^4.41.33", + "@types/webpack-env": "^1.18.4", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", "babel-jest": "^29.5.0", diff --git a/yarn.lock b/yarn.lock index 0b60c39c91..ffc64ba08c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2766,6 +2766,7 @@ __metadata: "@types/redux-immutable": "npm:^4.0.3" "@types/requestidlecallback": "npm:^0.3.5" "@types/webpack": "npm:^4.41.33" + "@types/webpack-env": "npm:^1.18.4" "@typescript-eslint/eslint-plugin": "npm:^7.0.0" "@typescript-eslint/parser": "npm:^7.0.0" arrow-key-navigation: "npm:^1.2.0" @@ -3990,6 +3991,13 @@ __metadata: languageName: node linkType: hard +"@types/webpack-env@npm:^1.18.4": + version: 1.18.4 + resolution: "@types/webpack-env@npm:1.18.4" + checksum: 10c0/3fa77dbff0ed71685404576b0a1cf74587567fe2ee1cfd11d56d6eefcab7a61e4c9ead0eced264e289d2cf0fc74296dbd55ed6c95774fe0fd6264d156c5a59f0 + languageName: node + linkType: hard + "@types/webpack-sources@npm:*": version: 3.2.2 resolution: "@types/webpack-sources@npm:3.2.2" From d8a4cea41b7def0815912cfba01aee7f95a24cde Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:08:43 +0200 Subject: [PATCH 026/658] Update dependency haml_lint to v0.58.0 (#30094) 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 18564ea68b..f575623700 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -304,7 +304,7 @@ GEM activesupport (>= 5.1) haml (>= 4.0.6) railties (>= 5.1) - haml_lint (0.57.0) + haml_lint (0.58.0) haml (>= 5.0) parallel (~> 1.10) rainbow @@ -498,7 +498,7 @@ GEM orm_adapter (0.5.0) ox (2.14.18) parallel (1.24.0) - parser (3.3.0.5) + parser (3.3.1.0) ast (~> 2.4.1) racc parslet (2.0.0) From 31f3dd57e08282b679bb0033b6b69f0172fde678 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:08:58 +0200 Subject: [PATCH 027/658] Update dependency rubocop to v1.63.4 (#30096) 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 f575623700..4f4ca89dc2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -644,7 +644,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 8) rspec-support (3.13.1) - rubocop (1.63.3) + rubocop (1.63.4) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) From c0584a6f4f91c00b28bf6a1e307c0f0228b5ad67 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 08:09:27 +0000 Subject: [PATCH 028/658] Update devDependencies (non-major) (#30109) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/yarn.lock b/yarn.lock index ffc64ba08c..0ef97cdd84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1983,7 +1983,7 @@ __metadata: languageName: node linkType: hard -"@csstools/selector-specificity@npm:^3.0.2, @csstools/selector-specificity@npm:^3.0.3": +"@csstools/selector-specificity@npm:^3.0.3": version: 3.0.3 resolution: "@csstools/selector-specificity@npm:3.0.3" peerDependencies: @@ -3332,8 +3332,8 @@ __metadata: linkType: hard "@testing-library/react@npm:^15.0.0": - version: 15.0.2 - resolution: "@testing-library/react@npm:15.0.2" + version: 15.0.5 + resolution: "@testing-library/react@npm:15.0.5" dependencies: "@babel/runtime": "npm:^7.12.5" "@testing-library/dom": "npm:^10.0.0" @@ -3341,7 +3341,7 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 10c0/8d75e4850f8f749244bf4f30b0f99a5d4aa1156ee5a59eea0772f47971c38535d1fb31d021c4f0f0b816346ae664870dc223d5d997ab399dfb1b6211f0e2acf1 + checksum: 10c0/8759cc8e7e6b4d8964f151d8872ea3c91b6ef6d8fb3b9116fae53350b9a6b29e5ad45b18408c22525924d050263f7ea77cd17ca803918759f22a760f68a42227 languageName: node linkType: hard @@ -6509,10 +6509,10 @@ __metadata: languageName: node linkType: hard -"css-functions-list@npm:^3.2.1": - version: 3.2.1 - resolution: "css-functions-list@npm:3.2.1" - checksum: 10c0/e6e2d9580437ad6df9f2cf18cff3f941691ec5cbbaebd4cb17a5da40d8d5dac50004807ddd05c00a121d2f21a224e2c5d339fe8e13614af21c00181d7d1c22b9 +"css-functions-list@npm:^3.2.2": + version: 3.2.2 + resolution: "css-functions-list@npm:3.2.2" + checksum: 10c0/8638a63d0cf1bdc50d4a752ec1c94a57e9953c3b03eace4f5526db20bec3c061e95089f905dbb4999c44b9780ce777ba856967560f6d15119a303f6030901c10 languageName: node linkType: hard @@ -14329,10 +14329,10 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.0.0, react-is@npm:^18.2.0": - version: 18.2.0 - resolution: "react-is@npm:18.2.0" - checksum: 10c0/6eb5e4b28028c23e2bfcf73371e72cd4162e4ac7ab445ddae2afe24e347a37d6dc22fae6e1748632cd43c6d4f9b8f86dcf26bf9275e1874f436d129952528ae0 +"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.0.0, react-is@npm:^18.3.1": + version: 18.3.1 + resolution: "react-is@npm:18.3.1" + checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072 languageName: node linkType: hard @@ -14581,15 +14581,15 @@ __metadata: linkType: hard "react-test-renderer@npm:^18.2.0": - version: 18.2.0 - resolution: "react-test-renderer@npm:18.2.0" + version: 18.3.1 + resolution: "react-test-renderer@npm:18.3.1" dependencies: - react-is: "npm:^18.2.0" + react-is: "npm:^18.3.1" react-shallow-renderer: "npm:^16.15.0" - scheduler: "npm:^0.23.0" + scheduler: "npm:^0.23.2" peerDependencies: - react: ^18.2.0 - checksum: 10c0/53dfada1da1e8dd0498a5601e9eea3dc6ca23c6c2694d1cab9712faea869c11e4ce1c9a618d674cb668a668b41fb6bcf9a7b0a078cd853b1922f002fa22f42c8 + react: ^18.3.1 + checksum: 10c0/c633558ef9af33bc68f0c4dbb5163a004c4fb9eade7bd0a7cfc0355fb367f36bd9d96533c90b7e85a146be6c525113a15f58683d269e0177ad77e2b04d4fe51c languageName: node linkType: hard @@ -15314,12 +15314,12 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.23.0": - version: 0.23.0 - resolution: "scheduler@npm:0.23.0" +"scheduler@npm:^0.23.0, scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" dependencies: loose-envify: "npm:^1.1.0" - checksum: 10c0/b777f7ca0115e6d93e126ac490dbd82642d14983b3079f58f35519d992fa46260be7d6e6cede433a92db70306310c6f5f06e144f0e40c484199e09c1f7be53dd + checksum: 10c0/26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78 languageName: node linkType: hard @@ -16408,18 +16408,18 @@ __metadata: linkType: hard "stylelint@npm:^16.0.2": - version: 16.3.1 - resolution: "stylelint@npm:16.3.1" + version: 16.4.0 + resolution: "stylelint@npm:16.4.0" dependencies: "@csstools/css-parser-algorithms": "npm:^2.6.1" "@csstools/css-tokenizer": "npm:^2.2.4" "@csstools/media-query-list-parser": "npm:^2.1.9" - "@csstools/selector-specificity": "npm:^3.0.2" + "@csstools/selector-specificity": "npm:^3.0.3" "@dual-bundle/import-meta-resolve": "npm:^4.0.0" balanced-match: "npm:^2.0.0" colord: "npm:^2.9.3" cosmiconfig: "npm:^9.0.0" - css-functions-list: "npm:^3.2.1" + css-functions-list: "npm:^3.2.2" css-tree: "npm:^2.3.1" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" @@ -16448,11 +16448,11 @@ __metadata: strip-ansi: "npm:^7.1.0" supports-hyperlinks: "npm:^3.0.0" svg-tags: "npm:^1.0.0" - table: "npm:^6.8.1" + table: "npm:^6.8.2" write-file-atomic: "npm:^5.0.1" bin: stylelint: bin/stylelint.mjs - checksum: 10c0/1660bb359002ff8e07cea044018b13abc73f48cf02a5062953b086f4d58611cd10677787560774c1acabeb192b6d059ce7fcf4c11defa7f64e50dca908fc664f + checksum: 10c0/7e603a0d88732180b60528c9f2edfca7fdf8c966f42c260af16131854c3acb5acfa30403b1f4fd72cd1470eb9ba625ca4de84e8cb379942df54127c55afc1288 languageName: node linkType: hard @@ -16584,16 +16584,16 @@ __metadata: languageName: node linkType: hard -"table@npm:^6.8.1": - version: 6.8.1 - resolution: "table@npm:6.8.1" +"table@npm:^6.8.2": + version: 6.8.2 + resolution: "table@npm:6.8.2" dependencies: ajv: "npm:^8.0.1" lodash.truncate: "npm:^4.4.2" slice-ansi: "npm:^4.0.0" string-width: "npm:^4.2.3" strip-ansi: "npm:^6.0.1" - checksum: 10c0/591ed84b2438b01c9bc02248e2238e21e8bfb73654bc5acca0d469053eb39be3db2f57d600dcf08ac983b6f50f80842c44612c03877567c2afee3aec4a033e5f + checksum: 10c0/f8b348af38ee34e419d8ce7306ba00671ce6f20e861ccff22555f491ba264e8416086063ce278a8d81abfa8d23b736ec2cca7ac4029b5472f63daa4b4688b803 languageName: node linkType: hard From 23223369e083a38e0234c9c9552ddfebba967ad8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:09:50 +0200 Subject: [PATCH 029/658] Update eslint (non-major) (#30110) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 102 +++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0ef97cdd84..e8f4075e22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4049,14 +4049,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^7.0.0": - version: 7.7.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.7.0" + version: 7.7.1 + resolution: "@typescript-eslint/eslint-plugin@npm:7.7.1" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.7.0" - "@typescript-eslint/type-utils": "npm:7.7.0" - "@typescript-eslint/utils": "npm:7.7.0" - "@typescript-eslint/visitor-keys": "npm:7.7.0" + "@typescript-eslint/scope-manager": "npm:7.7.1" + "@typescript-eslint/type-utils": "npm:7.7.1" + "@typescript-eslint/utils": "npm:7.7.1" + "@typescript-eslint/visitor-keys": "npm:7.7.1" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" @@ -4069,25 +4069,25 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/d1f4c40523d284bce4b8272750c68aae5c0289ddb1c9267dd3477e0bfb8c8855bfb0c6e86dfec9911ca8302ef729d5f4e47d686a566f363b0f89bf7dc7670b5c + checksum: 10c0/11a085240e7daf4bdeb011aa53ac7cfeea6263c60d53607823f5c314eb5c9d559b28fce0d6686acb9702ee3d0cb0406534fafae61163e5a903eaf818c48194ad languageName: node linkType: hard "@typescript-eslint/parser@npm:^7.0.0": - version: 7.7.0 - resolution: "@typescript-eslint/parser@npm:7.7.0" + version: 7.7.1 + resolution: "@typescript-eslint/parser@npm:7.7.1" dependencies: - "@typescript-eslint/scope-manager": "npm:7.7.0" - "@typescript-eslint/types": "npm:7.7.0" - "@typescript-eslint/typescript-estree": "npm:7.7.0" - "@typescript-eslint/visitor-keys": "npm:7.7.0" + "@typescript-eslint/scope-manager": "npm:7.7.1" + "@typescript-eslint/types": "npm:7.7.1" + "@typescript-eslint/typescript-estree": "npm:7.7.1" + "@typescript-eslint/visitor-keys": "npm:7.7.1" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/d756c2292737499a93913647af7493aded5dc720a5f4ab6f8e96d6cc81f19cf6a1769a1df0f516f8facd276d34f8464f1711e57b0216082e32eb6b75da81b12e + checksum: 10c0/ace43eeb8123bbee61e936650e1d57a2cf70f2030870c6dcad8602fce3f7cdf2cce350121dbbc66cffd60bac36652f426a1c5293c45ed28998b90cd95673b5c9 languageName: node linkType: hard @@ -4101,22 +4101,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/scope-manager@npm:7.7.0" +"@typescript-eslint/scope-manager@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/scope-manager@npm:7.7.1" dependencies: - "@typescript-eslint/types": "npm:7.7.0" - "@typescript-eslint/visitor-keys": "npm:7.7.0" - checksum: 10c0/014a3631c12bfbd5e33146a48e4b9eb5cc1c5c95bb458de33f8847eed33c04d7b9e66283971e48297673c4b92c3239d67e6dc3717efbe5836e0269a538c13d2e + "@typescript-eslint/types": "npm:7.7.1" + "@typescript-eslint/visitor-keys": "npm:7.7.1" + checksum: 10c0/4032da8fce8922044a6b659c8435ba203377778d5b7de6a5572c1172f2e3cf8ddd890a0f9e083c5d5315a9c2dba323707528ee4ad3cc1be2bd334de2527ef5cb languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/type-utils@npm:7.7.0" +"@typescript-eslint/type-utils@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/type-utils@npm:7.7.1" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.7.0" - "@typescript-eslint/utils": "npm:7.7.0" + "@typescript-eslint/typescript-estree": "npm:7.7.1" + "@typescript-eslint/utils": "npm:7.7.1" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependencies: @@ -4124,7 +4124,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/064c28d4087a97fd175e07e02c0a9cf4526f61cc6a17b4199fba626932979210037643a30f868bda8174fad567a8ac6aed34120631d1ecfd502e0ea1e830f9e9 + checksum: 10c0/bd083c4106e207aa8c2a71251eca52d23c7ea905399b8c62004f3bb1e85b9c88d601db9dcecae88beef0f8362d53450bb2721aab353ee731c1665496fea3fbda languageName: node linkType: hard @@ -4135,10 +4135,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/types@npm:7.7.0" - checksum: 10c0/eb50793650c9a911c73586150807912e7b7a0ae12eeb26c7a322ac8ebb8edef15960cc9a4b7049dbb89b82500079963145f67d15583f5de270fe8290974db533 +"@typescript-eslint/types@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/types@npm:7.7.1" + checksum: 10c0/7d240503d9d0b12d68c8204167690609f02ededb77dcb035c1c8b932da08cf43553829c29a5f7889824a7337463c300343bc5abe532479726d4c83443a7e2704 languageName: node linkType: hard @@ -4161,12 +4161,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.7.0" +"@typescript-eslint/typescript-estree@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/typescript-estree@npm:7.7.1" dependencies: - "@typescript-eslint/types": "npm:7.7.0" - "@typescript-eslint/visitor-keys": "npm:7.7.0" + "@typescript-eslint/types": "npm:7.7.1" + "@typescript-eslint/visitor-keys": "npm:7.7.1" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -4176,24 +4176,24 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/19da9bf0948c9800fde19c5a408a80a3a4cf357ff67d47b516df5d2a05701a4fdd2b9ab5b692866bd84bfc17cea9132d1575a1423e01763a4c2918b5d77d0b34 + checksum: 10c0/c6b32bd96fd13b9da0a30de01935066f7505f6214f5759e3cd019f7d1852f7bf19358765f62e51de72be47647656aa0e8f07ac0ab316c4149a4e6bd1dd12cbb6 languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/utils@npm:7.7.0" +"@typescript-eslint/utils@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/utils@npm:7.7.1" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.15" "@types/semver": "npm:^7.5.8" - "@typescript-eslint/scope-manager": "npm:7.7.0" - "@typescript-eslint/types": "npm:7.7.0" - "@typescript-eslint/typescript-estree": "npm:7.7.0" + "@typescript-eslint/scope-manager": "npm:7.7.1" + "@typescript-eslint/types": "npm:7.7.1" + "@typescript-eslint/typescript-estree": "npm:7.7.1" semver: "npm:^7.6.0" peerDependencies: eslint: ^8.56.0 - checksum: 10c0/c5f18ce198b420bdc201fd4278b4fa97bfe86178db565f3c4e1991bb452c9ea0b657e7980572555e2ec2fe218d07c42c794d217b9369903019cf784eea7e2164 + checksum: 10c0/0986b8c297d6bfdbd2ac8cd3bcf447ef9b934e2dae536771d3368a5c284a0b16c0ea041f82aa100c48d05acc33198e1a3d9d721d3319ae80abba0f5e69c21633 languageName: node linkType: hard @@ -4224,13 +4224,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.7.0": - version: 7.7.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.7.0" +"@typescript-eslint/visitor-keys@npm:7.7.1": + version: 7.7.1 + resolution: "@typescript-eslint/visitor-keys@npm:7.7.1" dependencies: - "@typescript-eslint/types": "npm:7.7.0" + "@typescript-eslint/types": "npm:7.7.1" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/0f3b9720a962c04462a75d4872714c07320c8f672841881ada797ae960f9f6bd0e5f7494178917034f42635ef76f0f09fa3c8d4bd84f31ec58ee968fe75bada7 + checksum: 10c0/19cbd14ac9a234d847f457cbd880cbd98b83c331a46d2dc2d8c0e6cb54ce6159552f6dd2f7236035be1a71f13f48df4a2aa09e70ad1f1e2ff3da7c3622927bd3 languageName: node linkType: hard @@ -7816,11 +7816,11 @@ __metadata: linkType: hard "eslint-plugin-react-hooks@npm:^4.6.0": - version: 4.6.0 - resolution: "eslint-plugin-react-hooks@npm:4.6.0" + version: 4.6.2 + resolution: "eslint-plugin-react-hooks@npm:4.6.2" peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 10c0/58c7e10ea5792c33346fcf5cb4024e14837035ce412ff99c2dcb7c4f903dc9b17939078f80bfef826301ce326582c396c00e8e0ac9d10ac2cde2b42d33763c65 + checksum: 10c0/4844e58c929bc05157fb70ba1e462e34f1f4abcbc8dd5bbe5b04513d33e2699effb8bca668297976ceea8e7ebee4e8fc29b9af9d131bcef52886feaa2308b2cc languageName: node linkType: hard From 0efa9854a1ff8123782ebc6a420d430da4a3c7a1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:10:04 +0200 Subject: [PATCH 030/658] Update libretranslate/libretranslate Docker tag to v1.5.7 (#30111) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index d14af5d7d9..97331f74ea 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -70,7 +70,7 @@ services: hard: -1 libretranslate: - image: libretranslate/libretranslate:v1.5.6 + image: libretranslate/libretranslate:v1.5.7 restart: unless-stopped volumes: - lt-data:/home/libretranslate/.local From 00aec2f33a03e173e8e4a2de346846e8388686ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 08:10:20 +0000 Subject: [PATCH 031/658] Update peter-evans/create-pull-request action to v6.0.5 (#30112) 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 256dcffc77..1df7672d6c 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@v6.0.4 + uses: peter-evans/create-pull-request@v6.0.5 with: commit-message: 'New Crowdin translations' title: 'New Crowdin Translations (automated)' From 9be7efedf09491fefc5c287a1c67660eb7a6b633 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 08:15:43 +0000 Subject: [PATCH 032/658] New Crowdin Translations (automated) (#30092) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/bg.json | 13 +++++++++++++ app/javascript/mastodon/locales/br.json | 3 +++ app/javascript/mastodon/locales/ca.json | 10 +++++++++- app/javascript/mastodon/locales/cs.json | 13 +++++++++++++ app/javascript/mastodon/locales/es-AR.json | 15 ++++++++++++++- app/javascript/mastodon/locales/es-MX.json | 13 +++++++++++++ app/javascript/mastodon/locales/es.json | 13 +++++++++++++ app/javascript/mastodon/locales/he.json | 9 +++++++++ app/javascript/mastodon/locales/hu.json | 6 +++--- app/javascript/mastodon/locales/ja.json | 4 ++++ app/javascript/mastodon/locales/ko.json | 13 +++++++++++++ app/javascript/mastodon/locales/lad.json | 4 ++++ app/javascript/mastodon/locales/sk.json | 2 ++ app/javascript/mastodon/locales/sv.json | 9 +++++++++ app/javascript/mastodon/locales/th.json | 15 ++++++++++++++- app/javascript/mastodon/locales/tr.json | 13 +++++++++++++ app/javascript/mastodon/locales/vi.json | 13 +++++++++++++ app/javascript/mastodon/locales/zh-HK.json | 13 +++++++++++++ config/locales/be.yml | 8 ++++++++ config/locales/bg.yml | 1 + config/locales/br.yml | 2 ++ config/locales/ca.yml | 1 + config/locales/cs.yml | 1 + config/locales/da.yml | 1 + config/locales/de.yml | 1 + config/locales/doorkeeper.be.yml | 1 + config/locales/doorkeeper.cs.yml | 1 + config/locales/doorkeeper.ja.yml | 1 + config/locales/doorkeeper.th.yml | 1 + config/locales/es-AR.yml | 1 + config/locales/es-MX.yml | 1 + config/locales/es.yml | 5 +++-- config/locales/eu.yml | 1 + config/locales/fi.yml | 1 + config/locales/fo.yml | 1 + config/locales/he.yml | 1 + config/locales/hu.yml | 1 + config/locales/is.yml | 1 + config/locales/it.yml | 1 + config/locales/nl.yml | 3 ++- config/locales/nn.yml | 1 + config/locales/pl.yml | 1 + config/locales/simple_form.an.yml | 4 ---- config/locales/simple_form.ar.yml | 4 ---- config/locales/simple_form.ast.yml | 3 --- config/locales/simple_form.be.yml | 4 ---- config/locales/simple_form.bg.yml | 8 ++++---- config/locales/simple_form.ca.yml | 8 ++++---- config/locales/simple_form.cs.yml | 8 ++++---- config/locales/simple_form.cy.yml | 4 ---- config/locales/simple_form.da.yml | 8 ++++---- config/locales/simple_form.de.yml | 8 ++++---- config/locales/simple_form.el.yml | 4 ---- config/locales/simple_form.en-GB.yml | 4 ---- config/locales/simple_form.eo.yml | 4 ---- config/locales/simple_form.es-AR.yml | 8 ++++---- config/locales/simple_form.es-MX.yml | 8 ++++---- config/locales/simple_form.es.yml | 8 ++++---- config/locales/simple_form.et.yml | 4 ---- config/locales/simple_form.eu.yml | 8 ++++---- config/locales/simple_form.fa.yml | 4 ---- config/locales/simple_form.fi.yml | 5 +---- config/locales/simple_form.fo.yml | 8 ++++---- config/locales/simple_form.fr-CA.yml | 4 ---- config/locales/simple_form.fr.yml | 4 ---- config/locales/simple_form.fy.yml | 4 ---- config/locales/simple_form.gd.yml | 4 ---- config/locales/simple_form.gl.yml | 4 ---- config/locales/simple_form.he.yml | 5 +---- config/locales/simple_form.hu.yml | 8 ++++---- config/locales/simple_form.id.yml | 4 ---- config/locales/simple_form.ie.yml | 4 ---- config/locales/simple_form.io.yml | 4 ---- config/locales/simple_form.is.yml | 6 ++---- config/locales/simple_form.it.yml | 8 ++++---- config/locales/simple_form.ja.yml | 4 ---- config/locales/simple_form.ko.yml | 4 ---- config/locales/simple_form.ku.yml | 4 ---- config/locales/simple_form.lad.yml | 4 ---- config/locales/simple_form.lt.yml | 2 -- config/locales/simple_form.lv.yml | 4 ---- config/locales/simple_form.ms.yml | 4 ---- config/locales/simple_form.my.yml | 4 ---- config/locales/simple_form.nl.yml | 8 ++++---- config/locales/simple_form.nn.yml | 8 ++++---- config/locales/simple_form.no.yml | 4 ---- config/locales/simple_form.pl.yml | 8 ++++---- config/locales/simple_form.pt-BR.yml | 4 ---- config/locales/simple_form.pt-PT.yml | 4 ---- config/locales/simple_form.ru.yml | 4 ---- config/locales/simple_form.sco.yml | 4 ---- config/locales/simple_form.sl.yml | 4 ---- config/locales/simple_form.sq.yml | 4 ---- config/locales/simple_form.sr-Latn.yml | 4 ---- config/locales/simple_form.sr.yml | 4 ---- config/locales/simple_form.sv.yml | 4 ---- config/locales/simple_form.th.yml | 5 +---- config/locales/simple_form.tr.yml | 8 ++++---- config/locales/simple_form.uk.yml | 8 +------- config/locales/simple_form.vi.yml | 8 ++++---- config/locales/simple_form.zh-CN.yml | 8 ++++---- config/locales/simple_form.zh-HK.yml | 8 ++++---- config/locales/simple_form.zh-TW.yml | 8 ++++---- config/locales/th.yml | 1 + config/locales/tr.yml | 1 + config/locales/uk.yml | 1 + config/locales/vi.yml | 1 + config/locales/zh-CN.yml | 1 + config/locales/zh-HK.yml | 1 + config/locales/zh-TW.yml | 1 + 110 files changed, 303 insertions(+), 253 deletions(-) diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index dabefd1f45..95d60b71eb 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Въпреки че акаунтът ви не е заключен, служителите на {domain} помислиха, че може да искате да преглеждате ръчно заявките за последване на тези профили.", "follow_suggestions.curated_suggestion": "Избор на персонал", "follow_suggestions.dismiss": "Без ново показване", + "follow_suggestions.featured_longer": "Ръчно избрано от отбора на {domain}", + "follow_suggestions.friends_of_friends_longer": "Популярно измежду хората, които следвате", "follow_suggestions.hints.featured": "Този профил е ръчно подбран от отбора на {domain}.", "follow_suggestions.hints.friends_of_friends": "Този профил е популярен измежду хората, които следвате.", "follow_suggestions.hints.most_followed": "Този профил е един от най-следваните при {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Този профил е подобен на профилите, които сте последвали наскоро.", "follow_suggestions.personalized_suggestion": "Персонализирано предложение", "follow_suggestions.popular_suggestion": "Популярно предложение", + "follow_suggestions.popular_suggestion_longer": "Популярно из {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Подобни на профилите, които наскоро сте последвали", "follow_suggestions.view_all": "Преглед на всички", "follow_suggestions.who_to_follow": "Кого да се следва", "followed_tags": "Последвани хаштагове", @@ -469,6 +473,15 @@ "notification.follow": "{name} ви последва", "notification.follow_request": "{name} поиска да ви последва", "notification.mention": "{name} ви спомена", + "notification.moderation-warning.learn_more": "Научете повече", + "notification.moderation_warning": "Получихте предупреждение за модериране", + "notification.moderation_warning.action_delete_statuses": "Някои от публикациите ви са премахнати.", + "notification.moderation_warning.action_disable": "Вашият акаунт е изключен.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Някои от публикациите ви са означени като деликатни.", + "notification.moderation_warning.action_none": "Акаунтът ви получи предупреждение за модериране.", + "notification.moderation_warning.action_sensitive": "Публикациите ви ще се означават като деликатни от сега нататък.", + "notification.moderation_warning.action_silence": "Вашият акаунт е ограничен.", + "notification.moderation_warning.action_suspend": "Вашият акаунт е спрян.", "notification.own_poll": "Анкетата ви приключи", "notification.poll": "Анкета, в която гласувахте, приключи", "notification.reblog": "{name} подсили ваша публикация", diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json index f51121bcdc..9ec26c8c12 100644 --- a/app/javascript/mastodon/locales/br.json +++ b/app/javascript/mastodon/locales/br.json @@ -263,6 +263,8 @@ "follow_request.authorize": "Aotren", "follow_request.reject": "Nac'hañ", "follow_requests.unlocked_explanation": "Daoust ma n'eo ket ho kont prennet, skipailh {domain} a soñj e fellfe deoc'h gwiriekaat pedadennoù heuliañ deus ar c'hontoù-se diwar-zorn.", + "follow_suggestions.friends_of_friends_longer": "Diouzh ar c'hiz e-touez an dud heuliet ganeoc'h", + "follow_suggestions.popular_suggestion_longer": "Diouzh ar c'hiz war {domain}", "follow_suggestions.view_all": "Gwelet pep tra", "followed_tags": "Hashtagoù o heuliañ", "footer.about": "Diwar-benn", @@ -395,6 +397,7 @@ "notification.follow": "heuliañ a ra {name} ac'hanoc'h", "notification.follow_request": "Gant {name} eo bet goulennet ho heuliañ", "notification.mention": "Gant {name} oc'h bet meneget", + "notification.moderation-warning.learn_more": "Gouzout hiroc'h", "notification.own_poll": "Echu eo ho sontadeg", "notification.poll": "Ur sontadeg ho deus mouezhet warnañ a zo echuet", "notification.reblog": "Gant {name} eo bet skignet ho toud", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 6dfe06a92e..25aeea9b46 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -318,7 +318,7 @@ "follow_suggestions.personalized_suggestion": "Suggeriment personalitzat", "follow_suggestions.popular_suggestion": "Suggeriment popular", "follow_suggestions.popular_suggestion_longer": "Popular a {domain}", - "follow_suggestions.similar_to_recently_followed_longer": "Semblant a perfils que has seguit fa poc", + "follow_suggestions.similar_to_recently_followed_longer": "Semblant a perfils que seguiu fa poc", "follow_suggestions.view_all": "Mostra-ho tot", "follow_suggestions.who_to_follow": "A qui seguir", "followed_tags": "Etiquetes seguides", @@ -473,6 +473,14 @@ "notification.follow": "{name} et segueix", "notification.follow_request": "{name} ha sol·licitat de seguir-te", "notification.mention": "{name} t'ha esmentat", + "notification.moderation_warning": "Heu rebut un avís de moderació", + "notification.moderation_warning.action_delete_statuses": "S'han eliminat algunes de les vostres publicacions.", + "notification.moderation_warning.action_disable": "S'ha desactivat el vostre compte.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "S'ha marcat com a sensibles algunes de les vostres publicacions.", + "notification.moderation_warning.action_none": "El vostre compte ha rebut un avís de moderació.", + "notification.moderation_warning.action_sensitive": "A partir d'ara les vostres publicacions es marcaran com sensibles.", + "notification.moderation_warning.action_silence": "S'ha limitat el vostre compte.", + "notification.moderation_warning.action_suspend": "S'ha suspès el vostre compte.", "notification.own_poll": "La teva enquesta ha finalitzat", "notification.poll": "Ha finalitzat una enquesta en què has votat", "notification.reblog": "{name} t'ha impulsat", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 2fc01f3acc..f2a1f023a3 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Přestože váš účet není uzamčen, personál {domain} usoudil, že byste mohli chtít tyto požadavky na sledování zkontrolovat ručně.", "follow_suggestions.curated_suggestion": "Výběr personálů", "follow_suggestions.dismiss": "Znovu nezobrazovat", + "follow_suggestions.featured_longer": "Ručně vybráno týmem {domain}", + "follow_suggestions.friends_of_friends_longer": "Populární mezi lidmi, které sledujete", "follow_suggestions.hints.featured": "Tento profil byl ručně vybrán týmem {domain}.", "follow_suggestions.hints.friends_of_friends": "Tento profil je populární mezi lidmi, které sledujete.", "follow_suggestions.hints.most_followed": "Tento profil je jedním z nejvíce sledovaných na {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Tento profil je podobný profilům, které jste nedávno sledovali.", "follow_suggestions.personalized_suggestion": "Přizpůsobený návrh", "follow_suggestions.popular_suggestion": "Populární návrh", + "follow_suggestions.popular_suggestion_longer": "Populární na {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Podobné profilům, které jste nedávno sledovali", "follow_suggestions.view_all": "Zobrazit vše", "follow_suggestions.who_to_follow": "Koho sledovat", "followed_tags": "Sledované hashtagy", @@ -469,6 +473,15 @@ "notification.follow": "Uživatel {name} vás začal sledovat", "notification.follow_request": "Uživatel {name} požádal o povolení vás sledovat", "notification.mention": "Uživatel {name} vás zmínil", + "notification.moderation-warning.learn_more": "Zjistit více", + "notification.moderation_warning": "Obdrželi jste moderační varování", + "notification.moderation_warning.action_delete_statuses": "Některé z vašich příspěvků byly odstraněny.", + "notification.moderation_warning.action_disable": "Váš účet je zablokován.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Některé z vašich příspěvků byly označeny jako citlivé.", + "notification.moderation_warning.action_none": "Váš účet obdržel moderační varování.", + "notification.moderation_warning.action_sensitive": "Vaše příspěvky budou od nynějška označeny jako citlivé.", + "notification.moderation_warning.action_silence": "Váš účet byl omezen.", + "notification.moderation_warning.action_suspend": "Váš účet byl pozastaven.", "notification.own_poll": "Vaše anketa skončila", "notification.poll": "Anketa, ve které jste hlasovali, skončila", "notification.reblog": "Uživatel {name} boostnul váš příspěvek", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 2cf4198625..2d42b3e949 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -241,7 +241,7 @@ "emoji_button.nature": "Naturaleza", "emoji_button.not_found": "No se encontraron emojis coincidentes", "emoji_button.objects": "Objetos", - "emoji_button.people": "Gente", + "emoji_button.people": "Cuentas", "emoji_button.recent": "Usados frecuentemente", "emoji_button.search": "Buscar...", "emoji_button.search_results": "Resultados de búsqueda", @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "A pesar de que tu cuenta no es privada, el equipo de {domain} pensó que podrías querer revisar manualmente las solicitudes de seguimiento de estas cuentas.", "follow_suggestions.curated_suggestion": "Selección del equipo", "follow_suggestions.dismiss": "No mostrar de nuevo", + "follow_suggestions.featured_longer": "Seleccionada a mano por el equipo de {domain}", + "follow_suggestions.friends_of_friends_longer": "Populares entre las cuentas que seguís", "follow_suggestions.hints.featured": "Este perfil fue seleccionado a mano por el equipo de {domain}.", "follow_suggestions.hints.friends_of_friends": "Este perfil es popular entre las cuentas que seguís.", "follow_suggestions.hints.most_followed": "Este perfil es uno de los más seguidos en {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Este perfil es similar a los que comenzaste a seguir.", "follow_suggestions.personalized_suggestion": "Sugerencia personalizada", "follow_suggestions.popular_suggestion": "Sugerencia popular", + "follow_suggestions.popular_suggestion_longer": "Popular en {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similares a perfiles que comenzaste a seguir recientemente", "follow_suggestions.view_all": "Ver todo", "follow_suggestions.who_to_follow": "A quién seguir", "followed_tags": "Etiquetas seguidas", @@ -469,6 +473,15 @@ "notification.follow": "{name} te empezó a seguir", "notification.follow_request": "{name} solicitó seguirte", "notification.mention": "{name} te mencionó", + "notification.moderation-warning.learn_more": "Aprendé más", + "notification.moderation_warning": "Recibiste una advertencia de moderación", + "notification.moderation_warning.action_delete_statuses": "Se eliminaron algunos de tus mensajes.", + "notification.moderation_warning.action_disable": "Se deshabilitó tu cuenta.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Se marcaron como sensibles a algunos de tus mensajes.", + "notification.moderation_warning.action_none": "Tu cuenta recibió una advertencia de moderación.", + "notification.moderation_warning.action_sensitive": "A partir de ahora, tus mensajes serán marcados como sensibles.", + "notification.moderation_warning.action_silence": "Tu cuenta fue limitada.", + "notification.moderation_warning.action_suspend": "Tu cuenta fue suspendida.", "notification.own_poll": "Tu encuesta finalizó", "notification.poll": "Finalizó una encuesta en la que votaste", "notification.reblog": "{name} adhirió a tu mensaje", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 1d8d4cedf8..b529f48ebe 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "A pesar de que tu cuenta no es privada, el personal de {domain} ha pensado que quizás deberías revisar manualmente las solicitudes de seguimiento de estas cuentas.", "follow_suggestions.curated_suggestion": "Recomendaciones del equipo", "follow_suggestions.dismiss": "No mostrar de nuevo", + "follow_suggestions.featured_longer": "Escogidos por el equipo de {domain}", + "follow_suggestions.friends_of_friends_longer": "Populares entre las personas a las que sigues", "follow_suggestions.hints.featured": "Este perfil ha sido seleccionado a mano por el equipo de {domain}.", "follow_suggestions.hints.friends_of_friends": "Este perfil es popular entre las personas que sigues.", "follow_suggestions.hints.most_followed": "Este perfil es uno de los más seguidos en {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Este perfil es similar a los perfiles que has seguido recientemente.", "follow_suggestions.personalized_suggestion": "Sugerencia personalizada", "follow_suggestions.popular_suggestion": "Sugerencia popular", + "follow_suggestions.popular_suggestion_longer": "Populares en {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similares a los perfiles que has seguido recientemente", "follow_suggestions.view_all": "Ver todo", "follow_suggestions.who_to_follow": "Recomendamos seguir", "followed_tags": "Hashtags seguidos", @@ -469,6 +473,15 @@ "notification.follow": "{name} te empezó a seguir", "notification.follow_request": "{name} ha solicitado seguirte", "notification.mention": "{name} te ha mencionado", + "notification.moderation-warning.learn_more": "Saber más", + "notification.moderation_warning": "Has recibido una advertencia de moderación", + "notification.moderation_warning.action_delete_statuses": "Se han eliminado algunas de tus publicaciones.", + "notification.moderation_warning.action_disable": "Se ha desactivado su cuenta.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Se han marcado como sensibles algunas de tus publicaciones.", + "notification.moderation_warning.action_none": "Tu cuenta ha recibido un aviso de moderación.", + "notification.moderation_warning.action_sensitive": "De ahora en adelante, todas tus publicaciones se marcarán como sensibles.", + "notification.moderation_warning.action_silence": "Se ha limitado tu cuenta.", + "notification.moderation_warning.action_suspend": "Se ha suspendido tu cuenta.", "notification.own_poll": "Tu encuesta ha terminado", "notification.poll": "Una encuesta en la que has votado ha terminado", "notification.reblog": "{name} ha retooteado tu estado", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 149a37d74e..ed01a33375 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "A pesar de que tu cuenta no es privada, el personal de {domain} ha pensado que quizás deberías revisar manualmente las solicitudes de seguimiento de estas cuentas.", "follow_suggestions.curated_suggestion": "Recomendaciones del equipo", "follow_suggestions.dismiss": "No mostrar de nuevo", + "follow_suggestions.featured_longer": "Escogidos por el equipo de {domain}", + "follow_suggestions.friends_of_friends_longer": "Populares entre las personas a las que sigues", "follow_suggestions.hints.featured": "Este perfil ha sido elegido a mano por el equipo de {domain}.", "follow_suggestions.hints.friends_of_friends": "Este perfil es popular entre las personas que sigues.", "follow_suggestions.hints.most_followed": "Este perfil es uno de los más seguidos en {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Este perfil es similar a los perfiles que has seguido recientemente.", "follow_suggestions.personalized_suggestion": "Sugerencia personalizada", "follow_suggestions.popular_suggestion": "Sugerencia popular", + "follow_suggestions.popular_suggestion_longer": "Populares en {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similares a los perfiles que has seguido recientemente", "follow_suggestions.view_all": "Ver todo", "follow_suggestions.who_to_follow": "A quién seguir", "followed_tags": "Etiquetas seguidas", @@ -469,6 +473,15 @@ "notification.follow": "{name} te empezó a seguir", "notification.follow_request": "{name} ha solicitado seguirte", "notification.mention": "{name} te ha mencionado", + "notification.moderation-warning.learn_more": "Saber más", + "notification.moderation_warning": "Has recibido una advertencia de moderación", + "notification.moderation_warning.action_delete_statuses": "Se han eliminado algunas de tus publicaciones.", + "notification.moderation_warning.action_disable": "Se ha desactivado su cuenta.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Se han marcado como sensibles algunas de tus publicaciones.", + "notification.moderation_warning.action_none": "Tu cuenta ha recibido un aviso de moderación.", + "notification.moderation_warning.action_sensitive": "De ahora en adelante, todas tus publicaciones se marcarán como sensibles.", + "notification.moderation_warning.action_silence": "Se ha limitado tu cuenta.", + "notification.moderation_warning.action_suspend": "Se ha suspendido tu cuenta.", "notification.own_poll": "Tu encuesta ha terminado", "notification.poll": "Una encuesta en la que has votado ha terminado", "notification.reblog": "{name} ha impulsado tu publicación", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 0b66a27fa9..600de39597 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -473,6 +473,15 @@ "notification.follow": "{name} במעקב אחרייך", "notification.follow_request": "{name} ביקשו לעקוב אחריך", "notification.mention": "אוזכרת על ידי {name}", + "notification.moderation-warning.learn_more": "למידע נוסף", + "notification.moderation_warning": "קיבלת אזהרה מצוות ניהול התוכן", + "notification.moderation_warning.action_delete_statuses": "חלק מהודעותיך הוסרו.", + "notification.moderation_warning.action_disable": "חשבונך הושבת.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "חלק מהודעותיך סומנו כרגישות.", + "notification.moderation_warning.action_none": "חשבונך קיבל אזהרה מצוות ניהול התוכן.", + "notification.moderation_warning.action_sensitive": "הודעותיך יסומנו כרגישות מעתה ואילך.", + "notification.moderation_warning.action_silence": "חשבונך הוגבל.", + "notification.moderation_warning.action_suspend": "חשבונך הושעה.", "notification.own_poll": "הסקר שלך הסתיים", "notification.poll": "סקר שהצבעת בו הסתיים", "notification.reblog": "הודעתך הודהדה על ידי {name}", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 42ce842585..ba7fd6ddc2 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -309,7 +309,7 @@ "follow_suggestions.curated_suggestion": "A stáb választása", "follow_suggestions.dismiss": "Ne jelenjen meg újra", "follow_suggestions.featured_longer": "A {domain} csapata által kézzel kiválasztott", - "follow_suggestions.friends_of_friends_longer": "Népszerű az Ön által követett emberek körében", + "follow_suggestions.friends_of_friends_longer": "Népszerű az általad követett emberek körében", "follow_suggestions.hints.featured": "Ezt a profilt a(z) {domain} csapata választotta ki.", "follow_suggestions.hints.friends_of_friends": "Ez a profil népszerű az általad követett emberek körében.", "follow_suggestions.hints.most_followed": "Ez a profil a leginkább követett a(z) {domain} oldalon.", @@ -318,7 +318,7 @@ "follow_suggestions.personalized_suggestion": "Személyre szabott javaslat", "follow_suggestions.popular_suggestion": "Népszerű javaslat", "follow_suggestions.popular_suggestion_longer": "Népszerű itt: {domain}", - "follow_suggestions.similar_to_recently_followed_longer": "Hasonló profilok, melyeket nemrég követett", + "follow_suggestions.similar_to_recently_followed_longer": "Hasonló azokhoz a profilokhoz, melyeket nemrég követtél be", "follow_suggestions.view_all": "Összes megtekintése", "follow_suggestions.who_to_follow": "Kit érdemes követni", "followed_tags": "Követett hashtagek", @@ -473,7 +473,7 @@ "notification.follow": "{name} követ téged", "notification.follow_request": "{name} követni szeretne téged", "notification.mention": "{name} megemlített", - "notification.moderation-warning.learn_more": "További információk", + "notification.moderation-warning.learn_more": "További információ", "notification.moderation_warning": "Moderációs figyelmeztetést kaptál", "notification.moderation_warning.action_delete_statuses": "Néhány bejegyzésedet eltávolították.", "notification.moderation_warning.action_disable": "A fiókod le van tiltva.", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index f20d93753b..6824a76a31 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "あなたのアカウントは承認制ではありませんが、{domain}のスタッフはこれらのアカウントからのフォローリクエストの確認が必要であると判断しました。", "follow_suggestions.curated_suggestion": "サーバースタッフ公認", "follow_suggestions.dismiss": "今後表示しない", + "follow_suggestions.featured_longer": "{domain} スタッフ公認", + "follow_suggestions.friends_of_friends_longer": "フォロー中のユーザーに人気", "follow_suggestions.hints.featured": "{domain} の運営スタッフが選んだアカウントです。", "follow_suggestions.hints.friends_of_friends": "フォロー中のユーザーのあいだで人気のアカウントです。", "follow_suggestions.hints.most_followed": "{domain} でもっともフォローされているアカウントのひとつです。", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "最近フォローしたユーザーに似ているアカウントです。", "follow_suggestions.personalized_suggestion": "フォローに基づく提案", "follow_suggestions.popular_suggestion": "人気のアカウント", + "follow_suggestions.popular_suggestion_longer": "{domain} で人気", + "follow_suggestions.similar_to_recently_followed_longer": "最近フォローしたユーザーと似ているアカウント", "follow_suggestions.view_all": "すべて表示", "follow_suggestions.who_to_follow": "フォローを増やしてみませんか?", "followed_tags": "フォロー中のハッシュタグ", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 8628dbb336..52ce9455a9 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "귀하의 계정이 잠긴 계정이 아닐지라도, {domain} 스태프는 이 계정들의 팔로우 요청을 수동으로 처리해 주시면 좋겠다고 생각했습니다.", "follow_suggestions.curated_suggestion": "스태프의 추천", "follow_suggestions.dismiss": "다시 보지 않기", + "follow_suggestions.featured_longer": "{domain} 팀이 손수 고름", + "follow_suggestions.friends_of_friends_longer": "내가 팔로우 하는 사람들 사이에서 인기", "follow_suggestions.hints.featured": "이 프로필은 {domain} 팀이 손수 선택했습니다.", "follow_suggestions.hints.friends_of_friends": "이 프로필은 내가 팔로우 하는 사람들에게서 유명합니다.", "follow_suggestions.hints.most_followed": "이 프로필은 {domain}에서 가장 많이 팔로우 된 사람들 중 하나입니다.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "이 프로필은 내가 최근에 팔로우 한 프로필들과 유사합니다.", "follow_suggestions.personalized_suggestion": "개인화된 추천", "follow_suggestions.popular_suggestion": "인기있는 추천", + "follow_suggestions.popular_suggestion_longer": "{domain}에서 인기", + "follow_suggestions.similar_to_recently_followed_longer": "내가 최근에 팔로우 한 프로필들과 유사", "follow_suggestions.view_all": "모두 보기", "follow_suggestions.who_to_follow": "팔로우할 만한 사람", "followed_tags": "팔로우 중인 해시태그", @@ -469,6 +473,15 @@ "notification.follow": "{name} 님이 나를 팔로우했습니다", "notification.follow_request": "{name} 님이 팔로우 요청을 보냈습니다", "notification.mention": "{name} 님의 멘션", + "notification.moderation-warning.learn_more": "더 알아보기", + "notification.moderation_warning": "중재 경고를 받았습니다", + "notification.moderation_warning.action_delete_statuses": "게시물 몇 개가 삭제되었습니다.", + "notification.moderation_warning.action_disable": "계정이 비활성화되었습니다.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "게시물 몇 개가 민감함 처리되었습니다.", + "notification.moderation_warning.action_none": "계정에 중재 경고를 받았습니다.", + "notification.moderation_warning.action_sensitive": "앞으로의 게시물을 민감한 것으로 표시됩니다.", + "notification.moderation_warning.action_silence": "계정이 제한되었습니다.", + "notification.moderation_warning.action_suspend": "계정이 정지되었습니다.", "notification.own_poll": "설문을 마침", "notification.poll": "참여한 설문이 종료됨", "notification.reblog": "{name} 님이 부스트했습니다", diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json index cf6c3f772f..533f074004 100644 --- a/app/javascript/mastodon/locales/lad.json +++ b/app/javascript/mastodon/locales/lad.json @@ -295,6 +295,7 @@ "follow_requests.unlocked_explanation": "Aunke tu kuento no esta serrado, la taifa de {domain} kreye ke talvez keres revizar manualmente las solisitudes de segimento de estos kuentos.", "follow_suggestions.curated_suggestion": "Seleksyon de la taifa", "follow_suggestions.dismiss": "No amostra mas", + "follow_suggestions.friends_of_friends_longer": "Popular entre personas a las kualas siges", "follow_suggestions.hints.featured": "Este profil tiene sido eskojido por la taifa de {domain}.", "follow_suggestions.hints.friends_of_friends": "Este profil es popular entre las personas ke siges.", "follow_suggestions.hints.most_followed": "Este profil es uno de los mas segidos en {domain}.", @@ -454,6 +455,9 @@ "notification.follow": "{name} te ampeso a segir", "notification.follow_request": "{name} tiene solisitado segirte", "notification.mention": "{name} te enmento", + "notification.moderation-warning.learn_more": "Ambezate mas", + "notification.moderation_warning.action_silence": "Tu kuento tiene sido limitado.", + "notification.moderation_warning.action_suspend": "Tu kuento tiene sido suspendido.", "notification.own_poll": "Tu anketa eskapo", "notification.poll": "Anketa en ke votates eskapo", "notification.reblog": "{name} repartajo tu publikasyon", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index d143fda52b..ea46b82235 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -293,6 +293,7 @@ "follow_suggestions.hints.similar_to_recently_followed": "Tento profil je podobný profilom, ktoré ste nedávno začali sledovať.", "follow_suggestions.personalized_suggestion": "Prispôsobený návrh", "follow_suggestions.popular_suggestion": "Obľúbený návrh", + "follow_suggestions.popular_suggestion_longer": "Populárne na {domain}", "follow_suggestions.view_all": "Zobraziť všetky", "follow_suggestions.who_to_follow": "Koho sledovať", "followed_tags": "Sledované hashtagy", @@ -442,6 +443,7 @@ "notification.follow": "{name} vás sleduje", "notification.follow_request": "{name} vás žiada sledovať", "notification.mention": "{name} vás spomína", + "notification.moderation-warning.learn_more": "Zisti viac", "notification.own_poll": "Vaša anketa sa skončila", "notification.poll": "Anketa, v ktorej ste hlasovali, sa skončila", "notification.reblog": "{name} zdieľa váš príspevok", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index c2dd5297db..5ac4b4648f 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -297,6 +297,7 @@ "filter_modal.select_filter.subtitle": "Använd en befintlig kategori eller skapa en ny", "filter_modal.select_filter.title": "Filtrera detta inlägg", "filter_modal.title.status": "Filtrera ett inlägg", + "filtered_notifications_banner.mentions": "{count, plural, one {omnämning} other {omnämnanden}}", "filtered_notifications_banner.pending_requests": "Aviseringar från {count, plural, =0 {ingen} one {en person} other {# personer}} du kanske känner", "filtered_notifications_banner.title": "Filtrerade aviseringar", "firehose.all": "Allt", @@ -307,6 +308,8 @@ "follow_requests.unlocked_explanation": "Även om ditt konto inte är låst tror {domain}-personalen att du kanske vill granska dessa följares förfrågningar manuellt.", "follow_suggestions.curated_suggestion": "Utvald av personalen", "follow_suggestions.dismiss": "Visa inte igen", + "follow_suggestions.featured_longer": "Handplockad av {domain}-teamet", + "follow_suggestions.friends_of_friends_longer": "Populärt bland personer du följer", "follow_suggestions.hints.featured": "Denna profil är handplockad av {domain}-teamet.", "follow_suggestions.hints.friends_of_friends": "Denna profil är populär bland de personer du följer.", "follow_suggestions.hints.most_followed": "Denna profil är en av de mest följda på {domain}.", @@ -314,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Denna profil liknar de profiler som du nyligen har följt.", "follow_suggestions.personalized_suggestion": "Personligt förslag", "follow_suggestions.popular_suggestion": "Populärt förslag", + "follow_suggestions.popular_suggestion_longer": "Populärt på {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Liknar profiler du nyligen följde", "follow_suggestions.view_all": "Visa alla", "follow_suggestions.who_to_follow": "Rekommenderade profiler", "followed_tags": "Följda hashtags", @@ -469,10 +474,14 @@ "notification.follow_request": "{name} har begärt att följa dig", "notification.mention": "{name} nämnde dig", "notification.moderation-warning.learn_more": "Läs mer", + "notification.moderation_warning": "Du har mottagit en modereringsvarning", "notification.moderation_warning.action_delete_statuses": "Några av dina inlägg har tagits bort.", "notification.moderation_warning.action_disable": "Ditt konto har inaktiverats.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Några av dina inlägg har markerats som känsliga.", + "notification.moderation_warning.action_none": "Ditt konto har mottagit en modereringsvarning.", + "notification.moderation_warning.action_sensitive": "Dina inlägg kommer markeras som känsliga från och med nu.", "notification.moderation_warning.action_silence": "Ditt konto har begränsats.", + "notification.moderation_warning.action_suspend": "Ditt konto har stängts av.", "notification.own_poll": "Din röstning har avslutats", "notification.poll": "En omröstning du röstat i har avslutats", "notification.reblog": "{name} boostade ditt inlägg", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 379aebbb1f..7c6b2ade4e 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -308,13 +308,17 @@ "follow_requests.unlocked_explanation": "แม้ว่าไม่มีการล็อคบัญชีของคุณ พนักงานของ {domain} คิดว่าคุณอาจต้องการตรวจทานคำขอติดตามจากบัญชีเหล่านี้ด้วยตนเอง", "follow_suggestions.curated_suggestion": "คัดสรรโดยพนักงาน", "follow_suggestions.dismiss": "ไม่ต้องแสดงอีก", + "follow_suggestions.featured_longer": "คัดสรรโดยทีม {domain}", + "follow_suggestions.friends_of_friends_longer": "เป็นที่นิยมในหมู่ผู้คนที่คุณติดตาม", "follow_suggestions.hints.featured": "โปรไฟล์นี้ได้รับการคัดสรรโดยทีม {domain}", - "follow_suggestions.hints.friends_of_friends": "โปรไฟล์นี้ได้รับความนิยมในหมู่ผู้คนที่คุณติดตาม", + "follow_suggestions.hints.friends_of_friends": "โปรไฟล์นี้เป็นที่นิยมในหมู่ผู้คนที่คุณติดตาม", "follow_suggestions.hints.most_followed": "โปรไฟล์นี้เป็นหนึ่งในโปรไฟล์ที่ได้รับการติดตามมากที่สุดใน {domain}", "follow_suggestions.hints.most_interactions": "โปรไฟล์นี้เพิ่งได้รับความสนใจอย่างมากใน {domain}", "follow_suggestions.hints.similar_to_recently_followed": "โปรไฟล์นี้คล้ายกับโปรไฟล์ที่คุณได้ติดตามล่าสุด", "follow_suggestions.personalized_suggestion": "ข้อเสนอแนะเฉพาะบุคคล", "follow_suggestions.popular_suggestion": "ข้อเสนอแนะยอดนิยม", + "follow_suggestions.popular_suggestion_longer": "เป็นที่นิยมใน {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "คล้ายกับโปรไฟล์ที่คุณได้ติดตามล่าสุด", "follow_suggestions.view_all": "ดูทั้งหมด", "follow_suggestions.who_to_follow": "ติดตามใครดี", "followed_tags": "แฮชแท็กที่ติดตาม", @@ -469,6 +473,15 @@ "notification.follow": "{name} ได้ติดตามคุณ", "notification.follow_request": "{name} ได้ขอติดตามคุณ", "notification.mention": "{name} ได้กล่าวถึงคุณ", + "notification.moderation-warning.learn_more": "เรียนรู้เพิ่มเติม", + "notification.moderation_warning": "คุณได้รับคำเตือนการกลั่นกรอง", + "notification.moderation_warning.action_delete_statuses": "เอาโพสต์บางส่วนของคุณออกแล้ว", + "notification.moderation_warning.action_disable": "ปิดใช้งานบัญชีของคุณแล้ว", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "ทำเครื่องหมายโพสต์บางส่วนของคุณว่าละเอียดอ่อนแล้ว", + "notification.moderation_warning.action_none": "บัญชีของคุณได้รับคำเตือนการกลั่นกรอง", + "notification.moderation_warning.action_sensitive": "จะทำเครื่องหมายโพสต์ของคุณว่าละเอียดอ่อนนับจากนี้ไป", + "notification.moderation_warning.action_silence": "จำกัดบัญชีของคุณแล้ว", + "notification.moderation_warning.action_suspend": "ระงับบัญชีของคุณแล้ว", "notification.own_poll": "การสำรวจความคิดเห็นของคุณได้สิ้นสุดแล้ว", "notification.poll": "การสำรวจความคิดเห็นที่คุณได้ลงคะแนนได้สิ้นสุดแล้ว", "notification.reblog": "{name} ได้ดันโพสต์ของคุณ", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index dc07480ef6..c46080cfb2 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Hesabınız kilitli olmasa da, {domain} personeli bu hesaplardan gelen takip isteklerini gözden geçirmek isteyebileceğinizi düşündü.", "follow_suggestions.curated_suggestion": "Çalışanların seçtikleri", "follow_suggestions.dismiss": "Tekrar gösterme", + "follow_suggestions.featured_longer": "{domain} takımı tarafından elle seçildi", + "follow_suggestions.friends_of_friends_longer": "Takip ettiğiniz kişiler arasında popüler", "follow_suggestions.hints.featured": "Bu profil {domain} ekibi tarafından elle seçilmiştir.", "follow_suggestions.hints.friends_of_friends": "Bu profil takip ettiğiniz insanlar arasında popülerdir.", "follow_suggestions.hints.most_followed": "Bu, {domain} sunucusunda en fazla izlenen profildir.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Bu profil, son zamanlarda takip ettiğiniz profillere benziyor.", "follow_suggestions.personalized_suggestion": "Kişiselleşmiş öneriler", "follow_suggestions.popular_suggestion": "Popüler öneriler", + "follow_suggestions.popular_suggestion_longer": "{domain} üzerinde popüler", + "follow_suggestions.similar_to_recently_followed_longer": "Yakın zamanda takip ettiğiniz hesaplara benziyor", "follow_suggestions.view_all": "Tümünü gör", "follow_suggestions.who_to_follow": "Takip edebileceklerin", "followed_tags": "Takip edilen etiketler", @@ -469,6 +473,15 @@ "notification.follow": "{name} seni takip etti", "notification.follow_request": "{name} size takip isteği gönderdi", "notification.mention": "{name} senden bahsetti", + "notification.moderation-warning.learn_more": "Daha fazlası", + "notification.moderation_warning": "Bir denetim uyarısı aldınız", + "notification.moderation_warning.action_delete_statuses": "Bazı gönderileriniz kaldırıldı.", + "notification.moderation_warning.action_disable": "Hesabınız devre dışı bırakıldı.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Bazı gönderileriniz hassas olarak işaretlendi.", + "notification.moderation_warning.action_none": "Hesabınız bir denetim uyarısı aldı.", + "notification.moderation_warning.action_sensitive": "Gönderileriniz artık hassas olarak işaretlenecek.", + "notification.moderation_warning.action_silence": "Hesabınız sınırlandırıldı.", + "notification.moderation_warning.action_suspend": "Hesabınız askıya alındı.", "notification.own_poll": "Anketiniz sona erdi", "notification.poll": "Oy verdiğiniz bir anket sona erdi", "notification.reblog": "{name} gönderini yeniden paylaştı", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index e1f886b1f5..b188488f0b 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Mặc dù tài khoản của bạn đang ở chế độ công khai, quản trị viên của {domain} vẫn tin rằng bạn sẽ muốn xem lại yêu cầu theo dõi từ những người khác.", "follow_suggestions.curated_suggestion": "Gợi ý từ máy chủ", "follow_suggestions.dismiss": "Không hiện lại", + "follow_suggestions.featured_longer": "Tuyển chọn bởi {domain}", + "follow_suggestions.friends_of_friends_longer": "Nổi tiếng với những người mà bạn theo dõi", "follow_suggestions.hints.featured": "Người này được đội ngũ {domain} đề xuất.", "follow_suggestions.hints.friends_of_friends": "Người này nổi tiếng với những người bạn theo dõi.", "follow_suggestions.hints.most_followed": "Người này được theo dõi nhiều nhất trên {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Người này có nét giống những người mà bạn theo dõi gần đây.", "follow_suggestions.personalized_suggestion": "Gợi ý cá nhân hóa", "follow_suggestions.popular_suggestion": "Những người nổi tiếng", + "follow_suggestions.popular_suggestion_longer": "Nổi tiếng trên {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Tương tự những người mà bạn theo dõi gần đây", "follow_suggestions.view_all": "Xem tất cả", "follow_suggestions.who_to_follow": "Gợi ý theo dõi", "followed_tags": "Hashtag theo dõi", @@ -469,6 +473,15 @@ "notification.follow": "{name} theo dõi bạn", "notification.follow_request": "{name} yêu cầu theo dõi bạn", "notification.mention": "{name} nhắc đến bạn", + "notification.moderation-warning.learn_more": "Tìm hiểu", + "notification.moderation_warning": "Bạn đã nhận một cảnh báo kiểm duyệt", + "notification.moderation_warning.action_delete_statuses": "Một vài tút của bạn bị gỡ.", + "notification.moderation_warning.action_disable": "Tài khoản của bạn đã bị vô hiệu hóa.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Vài tút bạn bị đánh dấu nhạy cảm.", + "notification.moderation_warning.action_none": "Bạn đã nhận một cảnh báo kiểm duyệt.", + "notification.moderation_warning.action_sensitive": "Tút của bạn sẽ bị đánh dấu nhạy cảm kể từ bây giờ.", + "notification.moderation_warning.action_silence": "Tài khoản của bạn đã bị hạn chế.", + "notification.moderation_warning.action_suspend": "Tài khoản của bạn đã bị vô hiệu hóa.", "notification.own_poll": "Cuộc bình chọn của bạn đã kết thúc", "notification.poll": "Cuộc bình chọn đã kết thúc", "notification.reblog": "{name} đăng lại tút của bạn", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 3ca9a8d11e..6b08e40284 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "即使您的帳號未上鎖,{domain} 的工作人員認為您可能會想手動審核來自這些帳號的追蹤請求。", "follow_suggestions.curated_suggestion": "編輯精選", "follow_suggestions.dismiss": "不再顯示", + "follow_suggestions.featured_longer": "{domain} 團隊精選", + "follow_suggestions.friends_of_friends_longer": "受你的追蹤對象歡迎", "follow_suggestions.hints.featured": "這個人檔案是由 {domain} 團隊精挑細選。", "follow_suggestions.hints.friends_of_friends": "這個人檔案在你追蹤的人當中很受歡迎。", "follow_suggestions.hints.most_followed": "這個人檔案是在 {domain} 上最多追蹤之一。", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "這個人檔案與你最近追蹤的類似。", "follow_suggestions.personalized_suggestion": "個人化推薦", "follow_suggestions.popular_suggestion": "熱門推薦", + "follow_suggestions.popular_suggestion_longer": "{domain} 熱門", + "follow_suggestions.similar_to_recently_followed_longer": "與你最近追蹤的帳號相似", "follow_suggestions.view_all": "查看所有", "follow_suggestions.who_to_follow": "追蹤對象", "followed_tags": "已追蹤標籤", @@ -469,6 +473,15 @@ "notification.follow": "{name} 開始追蹤你", "notification.follow_request": "{name} 要求追蹤你", "notification.mention": "{name} 提及你", + "notification.moderation-warning.learn_more": "了解更多", + "notification.moderation_warning": "你收到一則審核警告", + "notification.moderation_warning.action_delete_statuses": "你的部份帖文已被刪除。", + "notification.moderation_warning.action_disable": "你的帳號已被停用。", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "你某些帖文已被標記為敏感內容。", + "notification.moderation_warning.action_none": "你的帳號收到一則審核警告。", + "notification.moderation_warning.action_sensitive": "從現在起,你的帖文將被標記為敏感內容。", + "notification.moderation_warning.action_silence": "你的帳號已受到限制。", + "notification.moderation_warning.action_suspend": "你的帳號已被停權。", "notification.own_poll": "你的投票已結束", "notification.poll": "你參與過的一個投票已經結束", "notification.reblog": "{name} 轉推你的文章", diff --git a/config/locales/be.yml b/config/locales/be.yml index cdfc9cb39c..13daa9897e 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -621,6 +621,9 @@ be: actions_description_html: Вырашыце, якія дзеянні распачаць, каб вырашыць гэтую скаргу. Калі вы прымеце меры пакарання ў дачыненні да ўліковага запісу, пра які паведамляецца, ім будзе адпраўлена апавяшчэнне па электроннай пошце, за выключэннем выпадкаў, калі выбрана катэгорыя Спам. actions_description_remote_html: Вырашыце як паступіць з гэтай скаргай. Гэта паўплывае толькі на тое як ваш сервер звязваецца з аддалёным уліковым запісам і апрацоўвае яго кантэнт. add_to_report: Дадаць яшчэ дэталяў да скаргі + already_suspended_badges: + local: Ужо прыпынена на гэтым сэрвэры + remote: Ужо прыпынена на іх сэрвэры are_you_sure: Вы ўпэўнены? assign_to_self: Прызначыць мне assigned: Прызначаны мадэратар @@ -1708,6 +1711,7 @@ be: preferences: Налады profile: Профіль relationships: Падпіскі і падпісчыкі + severed_relationships: Разрыў сувязяў statuses_cleanup: Аўтавыдаленне допісаў strikes: Папярэджанні мадэратараў two_factor_authentication: Двухфактарная аўтэнтыфікацыя @@ -1715,10 +1719,13 @@ be: severed_relationships: download: Спампаваць (%{count}) event_type: + account_suspension: Прыпыненне ўліковага запісу (%{target_name}) + domain_block: Прыпыненне сервера (%{target_name}) user_domain_block: Вы заблакіравалі %{target_name} lost_followers: Страчаныя падпісчыкі lost_follows: Страчаныя падпіскі preamble: Вы можаце страціць падпіскі і падпісчыкаў, калі заблакіруеце дамен або калі вашы мадэратары вырашаць прыпыніць зносіны з серверам. Калі гэта адбудзецца, вы зможаце загрузіць спіс страчаных зносін, каб праверыць іх і, магчыма, імпартаваць на іншы сервер. + purged: Інфармацыя аб гэтым серверы была выдалена адміністратарамі вашага сервера. type: Падзея statuses: attached: @@ -1825,6 +1832,7 @@ be: contrast: Mastodon (высокі кантраст) default: Mastodon (цёмная) mastodon-light: Mastodon (светлая) + system: Аўтаматычна (выкарыстоўваць сістэмную тэму) time: formats: default: "%d.%m.%Y %H:%M" diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 0c4ce3be49..f242039ed8 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -751,6 +751,7 @@ bg: desc_html: Това разчита на външни скриптове от hCaptcha, което може да е проблем за сигурността и поверителността. В допълнение това може да направи процеса на регистриране значимо по-малко достъпно за някои хора (особено с увреждания).. Заради тези причини, то обмислете алтернативни мерки такива като регистрация на базата на одобрение или на покана. title: Изисква се новите потребители да разгадават капчата, за да потвърдят акаунтите си content_retention: + danger_zone: Опасна зона preamble: Управление на това как съдържание, породено от потребители, се съхранява в Mastodon. title: Задържане на съдържание default_noindex: diff --git a/config/locales/br.yml b/config/locales/br.yml index fa6d266f62..03537a5b80 100644 --- a/config/locales/br.yml +++ b/config/locales/br.yml @@ -245,6 +245,8 @@ br: title: Diwar-benn appearance: title: Neuz + content_retention: + danger_zone: Takad dañjer discovery: title: Dizoloadur trends: Luskadoù diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 032dc1e35a..08fef73642 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -751,6 +751,7 @@ ca: desc_html: Això es basa en scripts externs de hCaptcha, que poden ser un problema de privacitat i seguretat. A més, això pot fer que el procés de registre sigui significativament menys accesible per algunes (especialment discapacitades) persones. Per aquestes raons, si us plau considera alternatives com ara registre amb aprovació necessària o basada en invitacions. title: Demana als nous usuaris que resolguin un CAPTCHA per a confirmar el seu compte content_retention: + danger_zone: Zona de perill preamble: Controla com es desa a Mastodon el contingut generat per l'usuari. title: Retenció de contingut default_noindex: diff --git a/config/locales/cs.yml b/config/locales/cs.yml index bccbb75c4d..5693077319 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -779,6 +779,7 @@ cs: desc_html: Toto spoléhá na externí skripty z hCaptcha, což může být budit obavy o bezpečnost a soukromí. Navíc to může způsobit, že proces registrace bude pro některé osoby (zejména se zdravotním postižením) hůře přístupný. Z těchto důvodů zvažte alternativní přístup, jako je schvalování registrace nebo pozvánky. title: Vyžadovat po nových uživatelích, aby vyřešili CAPTCHU pro potvrzení jejich účtu content_retention: + danger_zone: Nebezpečná zóna preamble: Určuje, jak je obsah generovaný uživatelem uložen v Mastodonu. title: Uchovávání obsahu default_noindex: diff --git a/config/locales/da.yml b/config/locales/da.yml index acab53d152..252d0e2b58 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -751,6 +751,7 @@ da: desc_html: Dette er afhængig af eksterne scripts fra hCaptcha, som kan være en sikkerhed og privatlivets fred. Derudover kan dette gøre registreringsprocessen betydeligt mindre tilgængelig for nogle (især deaktiveret) personer. Af disse grunde bedes De overveje alternative foranstaltninger såsom godkendelsesbaseret eller inviteret til at blive registreret. title: Kræv nye brugere for at løse en CAPTCHA for at bekræfte deres konto content_retention: + danger_zone: Farezone preamble: Styr, hvordan Mastodon gemmer brugergenereret indhold. title: Indholdsopbevaring default_noindex: diff --git a/config/locales/de.yml b/config/locales/de.yml index 923682ea12..b19315e394 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -751,6 +751,7 @@ de: desc_html: Dies beruht auf externen Skripten von hCaptcha, die ein Sicherheits- und Datenschutzproblem darstellen könnten. Darüber hinaus kann das den Registrierungsprozess für manche Menschen (insbesondere für Menschen mit Behinderung) erheblich erschweren. Aus diesen Gründen solltest du alternative Maßnahmen in Betracht ziehen, z. B. eine Registrierung basierend auf einer Einladung oder auf Genehmigungen. title: Neue Nutzer*innen müssen ein CAPTCHA lösen, um das Konto zu bestätigen content_retention: + danger_zone: Gefahrenzone preamble: Lege fest, wie lange Inhalte von Nutzer*innen auf deinem Mastodon-Server gespeichert bleiben. title: Cache & Archive default_noindex: diff --git a/config/locales/doorkeeper.be.yml b/config/locales/doorkeeper.be.yml index 748cbeafa1..5f0536c8da 100644 --- a/config/locales/doorkeeper.be.yml +++ b/config/locales/doorkeeper.be.yml @@ -174,6 +174,7 @@ be: read:filters: бачыць свае фільтры read:follows: бачыць свае падпіскі read:lists: бачыць свае спісы + read:me: чытайце толькі базавую інфармацыю аб сваім уліковым запісе read:mutes: бачыць свае ігнараванні read:notifications: бачыць свае абвесткі read:reports: бачыць свае скаргі diff --git a/config/locales/doorkeeper.cs.yml b/config/locales/doorkeeper.cs.yml index be2a4d971a..9719a9a246 100644 --- a/config/locales/doorkeeper.cs.yml +++ b/config/locales/doorkeeper.cs.yml @@ -174,6 +174,7 @@ cs: read:filters: vidět vaše filtry read:follows: vidět vaše sledování read:lists: vidět vaše seznamy + read:me: číst pouze základní informace vašeho účtu read:mutes: vidět vaše skrytí read:notifications: vidět vaše oznámení read:reports: vidět vaše hlášení diff --git a/config/locales/doorkeeper.ja.yml b/config/locales/doorkeeper.ja.yml index 62f2a3eb0a..af61dbdcb7 100644 --- a/config/locales/doorkeeper.ja.yml +++ b/config/locales/doorkeeper.ja.yml @@ -174,6 +174,7 @@ ja: read:filters: フィルターの読み取り read:follows: フォローの読み取り read:lists: リストの読み取り + read:me: 自分のアカウントの基本的な情報の読み取りのみ read:mutes: ミュートの読み取り read:notifications: 通知の読み取り read:reports: 通報の読み取り diff --git a/config/locales/doorkeeper.th.yml b/config/locales/doorkeeper.th.yml index 067e065588..8a28566a0d 100644 --- a/config/locales/doorkeeper.th.yml +++ b/config/locales/doorkeeper.th.yml @@ -174,6 +174,7 @@ th: read:filters: ดูตัวกรองของคุณ read:follows: ดูการติดตามของคุณ read:lists: ดูรายการของคุณ + read:me: อ่านเฉพาะข้อมูลพื้นฐานของบัญชีของคุณเท่านั้น read:mutes: ดูการซ่อนของคุณ read:notifications: ดูการแจ้งเตือนของคุณ read:reports: ดูรายงานของคุณ diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index 7bfe3b90ba..aa3668d92a 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -751,6 +751,7 @@ es-AR: desc_html: Esto depende de scripts externos de hCaptcha, que pueden ser una preocupación de seguridad y privacidad. Además, esto puede hacer el proceso de registro significativamente menos accesible para algunas personas (especialmente para gente con discapacidades). Por estas razones, por favor, considerá medidas alternativas, como el registro basado en la aprobación o la invitación. title: Solicitar a los nuevos usuarios que resuelvan una CAPTCHA para confirmar su cuenta content_retention: + danger_zone: Zona de peligro preamble: Controlá cómo el contenido generado por el usuario se almacena en Mastodon. title: Retención de contenido default_noindex: diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index 4d17de4d0a..6a306b07b0 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -751,6 +751,7 @@ es-MX: desc_html: Esto se basa en scripts externos de hCaptcha, que pueden suponer una preocupación de seguridad y privacidad. Además, esto puede volver el proceso de registro significativamente menos accesible para algunas personas (especialmente con discapacidades). Por estas razones, por favor, considera medidas alternativas como el registro por aprobación manual o con invitación. title: Solicita a los nuevos usuarios que resuelvan un CAPTCHA para confirmar su cuenta content_retention: + danger_zone: Zona peligrosa preamble: Controlar cómo el contenido generado por el usuario se almacena en Mastodon. title: Retención de contenido default_noindex: diff --git a/config/locales/es.yml b/config/locales/es.yml index 086e8e2ef6..e7db7c8b04 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -214,12 +214,12 @@ es: resend_user: Reenviar Correo de Confirmación reset_password_user: Restablecer Contraseña resolve_report: Resolver Reporte - sensitive_account: Marcar multimedia en tu cuenta como sensible + sensitive_account: Marcar cuenta como sensible silence_account: Silenciar Cuenta suspend_account: Suspender Cuenta unassigned_report: Desasignar Reporte unblock_email_account: Desbloquear dirección de correo - unsensitive_account: Desmarcar multimedia en tu cuenta como sensible + unsensitive_account: Desmarcar cuenta como sensible unsilence_account: Dejar de Silenciar Cuenta unsuspend_account: Dejar de Suspender Cuenta update_announcement: Actualizar Anuncio @@ -751,6 +751,7 @@ es: desc_html: Esto se basa en scripts externos de hCaptcha, que pueden suponer una preocupación de seguridad y privacidad. Además, esto puede volver el proceso de registro significativamente menos accesible para algunas personas (especialmente con discapacidades). Por estas razones, por favor, considera medidas alternativas como el registro por aprobación manual o con invitación. title: Solicita a los nuevos usuarios que resuelvan un CAPTCHA para confirmar su cuenta content_retention: + danger_zone: Zona peligrosa preamble: Controlar cómo el contenido generado por el usuario se almacena en Mastodon. title: Retención de contenido default_noindex: diff --git a/config/locales/eu.yml b/config/locales/eu.yml index a05aa3c92f..22ca8135d5 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -753,6 +753,7 @@ eu: desc_html: Hori egiteko hCaptcha-ko scriptak behar dira, hirugarrenenak izanik, segurtasun eta pribatutasun arazoak ekarri ditzaketeenak. Horrez gain, script horiengatik nabarmen zailagoa egiten zaie pertsona batzuei izena ematea (batez ere desgaitasunen bat duenei). Hori dela eta, hausnartu beste neurri batzuk hartu ditzakezun, esaterako onarpenean oinarritutako izen ematea, edo gonbidapenen bidezkoa. title: Eskatu erabiltzaile berriei CAPTCHA bat ebazteko beren kontua berresteko content_retention: + danger_zone: Eremu arriskutsua preamble: Kontrolatu erabiltzaileek sortutako edukia nola biltegiratzen den Mastodonen. title: Edukia atxikitzea default_noindex: diff --git a/config/locales/fi.yml b/config/locales/fi.yml index f82a592ec3..5f96f611b4 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -751,6 +751,7 @@ fi: desc_html: Tämä perustuu ulkoisiin skripteihin hCaptchasta, mikä voi olla turvallisuus- ja yksityisyysongelma. Lisäksi tämä voi tehdä rekisteröinnin ihmisille huomattavasti (erityisesti vammaisten) helpommaksi. Harkitse vaihtoehtoisia toimenpiteitä, kuten hyväksymisperusteista tai kutsupohjaista rekisteröintiä. title: Vaadi uusia käyttäjiä vahvistaamaan tilinsä ratkaisemalla CAPTCHA-vahvistus content_retention: + danger_zone: Vaaravyöhyke preamble: Määritä, miten käyttäjän luoma sisältö tallennetaan Mastodoniin. title: Sisällön säilyttäminen default_noindex: diff --git a/config/locales/fo.yml b/config/locales/fo.yml index b6c8b306f0..15c9c7dc04 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -751,6 +751,7 @@ fo: desc_html: Hetta er bundið at uttanhýsis skriptum frá hCaptcha, sum kann vera ein trygdar- og privatlívsváði. Harafturat, so kann hetta gera skrásetingartilgongdina munandi minni atkomuliga til summi (brekaði) fólk. Tískil eigur tú at umhugsa aðrar hættir sosum góðkenningar-grundaða ella innbjóðingar-grundaða skráseting. title: Set krav til nýggjar brúkarar at loysa eina CAPTHA fyri at vátta teirra kontu content_retention: + danger_zone: Vandaøki preamble: Stýr hvussu brúkara-skapt tilfar er goymt í Mastodon. title: Varðveitsla av tilfari default_noindex: diff --git a/config/locales/he.yml b/config/locales/he.yml index ddb3417ff8..14da27ec75 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -779,6 +779,7 @@ he: desc_html: אפשרות זו ניסמכת על קטעי קוד חיצוניים של hCaptcha שעלולים להיות סיכון אבטחה ופרטיות. בנוסף, זה עשוי להפוך את תהליך ההרשמה לבלתי נגיש לא.נשים, במיוחד בעלות ובעלי מוגבלויות. מסיבות אלו, כדאי לשקול חלופות כמו אשרור מנהלים ידני או הרשמה רק על בסיס הזמנה. title: לדרוש פתרון CAPTCHA כדי לאשרר למשתמשים את חשבונם content_retention: + danger_zone: אזור מסוכן preamble: שליטה על דרך אחסון תוכן המשתמשים במסטודון. title: תקופת השמירה של תכנים default_noindex: diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 43f7692531..c48d527caf 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -751,6 +751,7 @@ hu: desc_html: Ez hCaptcha-ból származó külső scripteket használ, mely biztonsági vagy adatvédelmi résnek bizonyulhat. Ezen kívül ez a regisztrációs folyamatot jelentősen megnehezítheti bizonyos (kifejezetten különleges szükségletű) emberek számára. Emiatt fontold meg más módszerek, mint pl. jóváhagyás-alapú vagy meghívásalapú regisztráció használatát. title: Az új felhasználóknak egy CAPTCHA-t kell megoldaniuk, hogy megerősítsék a fiókjuk regisztrációját content_retention: + danger_zone: Veszélyzóna preamble: A felhasználók által előállított tartalom Mastodonon való tárolásának szabályozása. title: Tartalom megtartása default_noindex: diff --git a/config/locales/is.yml b/config/locales/is.yml index ba1785d9e6..2eeba976bc 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -753,6 +753,7 @@ is: Aukinheldur gæti þetta gert nýskráningarferlið óaðgengilegra sumum (sérstaklega fyrir fatlaða). Þess vegna er rétt að skoða aðra valmöguleika svo sem nýskráningar háðar samþykki eða boði. title: Nýir notendur munu þurfa að standast Turing skynpróf til að staðfesta notendaaðganginn content_retention: + danger_zone: Hættusvæði preamble: Stýrðu hvernig efni frá notendum sé geymt í Mastodon. title: Geymsla efnis default_noindex: diff --git a/config/locales/it.yml b/config/locales/it.yml index f12735cfb1..bda681ac08 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -751,6 +751,7 @@ it: desc_html: Questo si basa su script esterni da hCaptcha, che possono rappresentare un problema di sicurezza e privacy. Inoltre, questo può rendere il processo di registrazione significativamente meno accessibile ad alcune persone (soprattutto disabili). Per questi motivi, prendi in considerazione misure alternative come la registrazione basata su approvazione o su invito. title: Richiedi ai nuovi utenti di risolvere un CAPTCHA per confermare il loro account content_retention: + danger_zone: Zona pericolosa preamble: Controlla come vengono memorizzati i contenuti generati dall'utente in Mastodon. title: Conservazione dei contenuti default_noindex: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 553c780beb..74dea29b0e 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -745,12 +745,13 @@ nl: preamble: Mastodons webomgeving aanpassen. title: Weergave branding: - preamble: De branding van jouw server laat zien hoe het met andere servers in het netwerk verschilt. Deze informatie wordt op verschillende plekken getoond, zoals in de webomgeving van Mastodon, in mobiele apps, in voorvertoningen op andere websites en berichten-apps, enz. Daarom is het belangrijk om de informatie helder, kort en beknopt te houden. + preamble: De branding van jouw server laat zien hoe het met andere servers in het netwerk verschilt. Deze informatie wordt op verschillende plekken getoond, zoals in de webomgeving van Mastodon, in mobiele apps, in linkvoorbeelden op andere websites en berichten-apps, enz. Daarom is het belangrijk om de informatie helder, kort en beknopt te houden. title: Branding captcha_enabled: desc_html: Dit is afhankelijk van externe scripts van hCaptcha, wat veiligheids- en privacyrisico's met zich mee kan brengen. Bovendien kan dit het registratieproces aanzienlijk minder toegankelijk maken voor sommige (vooral gehandicapte) mensen. Om deze redenen kun je het beste alternatieve maatregelen overwegen, zoals registratie op basis van goedkeuring of op uitnodiging. title: Nieuwe gebruikers dienen een CAPTCHA op te lossen om hun account te bevestigen content_retention: + danger_zone: Gevarenzone preamble: Toezicht houden op hoe berichten en media van gebruikers op Mastodon worden bewaard. title: Bewaartermijn berichten default_noindex: diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 8a7cb18a40..013674ca51 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -751,6 +751,7 @@ nn: desc_html: Dette baserer seg på eksterne skript frå hCaptcha, noko som kan vera eit tryggleiks- og personvernsproblem. I tillegg kan dette gjera registreringsprosessen monaleg mindre tilgjengeleg (særleg for folk med nedsett funksjonsevne). Dette gjer at du bør du vurdera alternative tiltak, som til dømes godkjennings- eller invitasjonsbasert registrering. title: Krev at nye brukarar løyser ein CAPTCHA for å bekrefte kontoen sin content_retention: + danger_zone: Faresone preamble: Styr korleis brukargenerert innhald blir lagra i Mastodon. title: Bevaring av innhald default_noindex: diff --git a/config/locales/pl.yml b/config/locales/pl.yml index d3d16fe373..7c037d7d00 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -779,6 +779,7 @@ pl: desc_html: Wymaga użycia zewnętrznych skryptów hCaptcha, co może negatywnie wpływać na bezpieczeństwo i prywatność. Może również przyczynić się do znaczącego utrudnienia procesu rejestracji niektórym, np. niepełnosprawnym, osobom. Dlatego sugeruje się używanie zaproszeń bądź ręcznie potwierdzanie kont. title: W celu potwierdzenia ich kont wymagaj rozwiązania zadania CAPTCHA przez nowych użytkowników content_retention: + danger_zone: Strefa niebezpieczeństwa preamble: Kontroluj, jak treści generowane przez użytkownika są przechowywane w Mastodon. title: Retencja treści default_noindex: diff --git a/config/locales/simple_form.an.yml b/config/locales/simple_form.an.yml index 6ec8380f2a..e409c39ae1 100644 --- a/config/locales/simple_form.an.yml +++ b/config/locales/simple_form.an.yml @@ -66,13 +66,10 @@ an: warn: Amagar lo conteniu filtrau dezaga d'una alvertencia mencionando lo titol d'o filtro form_admin_settings: activity_api_enabled: Conteyo de publicacions locals, usuarios activos y nuevos rechistros en periodos semanals - backups_retention_period: Mantener los fichers d'usuario cheneraus entre lo numero de días especificau. bootstrap_timeline_accounts: Estas cuentas amaneixerán en a parte superior d'as recomendacions d'os nuevos usuarios. closed_registrations_message: Amostrau quan los rechistros son zarraus - content_cache_retention_period: Las publicacions d'atros servidors s'eliminarán dimpués d'o numero especificau de días quan s'estableixca una valor positiva. Esto puede estar irreversible. custom_css: Puetz aplicar estilos personalizaus a la versión web de Mastodon. mascot: Reemplaza la ilustración en a interficie web abanzada. - media_cache_retention_period: Los fichers multimedia descargaus s'eliminarán dimpués d'o numero especificau de días quan s'estableixca una valor positiva, y se redescargarán baixo demanda. peers_api_enabled: Una lista de nombres de dominio que este servidor ha trobau en o Fediverso. Aquí no s'incluye garra dato sobre si federas con un servidor determinau, nomás que lo tuyo servidor lo conoixe. Esto ye emplegau per los servicios que replegan estatisticas sobre la federación en un sentiu cheneral. profile_directory: Lo directorio de perfils lista a totz los usuarios que han optado per que la suya cuenta pueda estar descubierta. require_invite_text: Quan los rechistros requieren aprebación manual, fa obligatoria la dentrada de texto "Per qué quiers unir-te?" en cuenta d'opcional @@ -221,7 +218,6 @@ an: backups_retention_period: Periodo de retención d'o fichero d'usuario bootstrap_timeline_accounts: Recomendar siempre estas cuentas a nuevos usuarios closed_registrations_message: Mensache personalizau quan los rechistros no son disponibles - content_cache_retention_period: Periodo de retención de caché de conteniu custom_css: CSS personalizau mascot: Mascota personalizada (legado) media_cache_retention_period: Periodo de retención de caché multimedia diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml index da27fd8dc4..29e525b2c8 100644 --- a/config/locales/simple_form.ar.yml +++ b/config/locales/simple_form.ar.yml @@ -77,13 +77,10 @@ ar: warn: إخفاء المحتوى الذي تم تصفيته خلف تحذير يذكر عنوان الفلتر form_admin_settings: activity_api_enabled: عدد المنشورات المحلية و المستخدمين الناشطين و التسجيلات الأسبوعية الجديدة - backups_retention_period: الاحتفاظ بأرشيف المستخدم الذي تم إنشاؤه لعدد محدد من الأيام. bootstrap_timeline_accounts: سيتم تثبيت هذه الحسابات على قمة التوصيات للمستخدمين الجدد. closed_registrations_message: ما سيعرض عند إغلاق التسجيلات - content_cache_retention_period: سيتم حذف كافة المنشورات والمعاد نشرها من الخوادم الأخرى بعد عدد الأيام المحدد. قد لا تكون بعض المنشورات قابلة للاسترداد. كافة الفواصل المرجعية والمفضلات والمعاد نشرها ذات الصلة سوف تضيع ويستحيل التراجع عن هذا الإجراء. custom_css: يمكنك تطبيق أساليب مخصصة على نسخة الويب من ماستدون. mascot: تجاوز الرسوم التوضيحية في واجهة الويب المتقدمة. - media_cache_retention_period: سيتم حذف ملفات الوسائط التي تم تنزيلها بعد عدد الأيام المحدد عند تعيينها إلى قيمة موجبة، وإعادة تنزيلها عند الطلب. peers_api_enabled: قائمة بأسماء النطاقات التي صادفها هذا الخادم في الفدرالية. لا توجد بيانات هنا حول ما إذا كنت تتحد مع خادم معين، فقط أن خادمك يعرف عنها. ويستخدم هذا الخدمات التي تجمع الإحصاءات المتعلقة بالاتحاد بشكل عام. profile_directory: دليل الملف الشخصي يسرد جميع المستخدمين الذين اختاروا الدخول ليكونوا قابلين للاكتشاف. require_invite_text: عندما تتطلب التسجيلات الموافقة اليدوية، اجعل إدخال النص "لماذا تريد الانضمام ؟" إلزاميا بدلا من اختياري @@ -243,7 +240,6 @@ ar: backups_retention_period: فترة الاحتفاظ بأرشيف المستخدم bootstrap_timeline_accounts: أوصي دائما بهذه الحسابات للمستخدمين الجدد closed_registrations_message: رسالة مخصصة عندما يكون التسجيل غير متاح - content_cache_retention_period: مدة الاحتفاظ بالتخزين المؤقت للوسائط custom_css: سي أس أس CSS مخصص mascot: جالب حظ مخصص (قديم) media_cache_retention_period: مدة الاحتفاظ بالتخزين المؤقت للوسائط diff --git a/config/locales/simple_form.ast.yml b/config/locales/simple_form.ast.yml index e396962567..d1950ab15f 100644 --- a/config/locales/simple_form.ast.yml +++ b/config/locales/simple_form.ast.yml @@ -33,11 +33,9 @@ ast: featured_tag: name: 'Equí tán dalgunes de les etiquetes qu''usesti apocayá:' form_admin_settings: - backups_retention_period: Caltién los archivos xeneraos polos perfiles demientres el númberu de díes especificáu. closed_registrations_message: Apaez cuando'l rexistru ta desactiváu custom_css: Pues aplicar estilos personalizaos a la versión web de Mastodon. mascot: Anula la ilustración na interfaz web avanzada. - media_cache_retention_period: Los ficheros multimedia baxaos desaníciense dempués del númberu de díes especificáu al configurar un valor positivu, ya vuelven baxase baxo demanda. require_invite_text: Cuando los rexistros riquen una aprobación manual, el campu «¿Por qué quies xunite?» vuélvese obligatoriu site_extended_description: Cualesquier tipu d'información adicional que pueda ser útil pa visitantes ya pa perfiles rexistraos. El testu pue estructurase cola sintaxis de Mastodon. site_short_description: Un descripción curtia qu'ayuda a identificar de forma única al sirvidor. ¿Quién lu lleva?, ¿pa quién ye? @@ -134,7 +132,6 @@ ast: form_admin_settings: backups_retention_period: Periodu de retención de los archivos de los perfiles closed_registrations_message: Mensaxe personalizáu cuando'l rexistru nun ta disponible - content_cache_retention_period: Periodu de retención de la caché de conteníu media_cache_retention_period: Periodu de retención de la caché multimedia registrations_mode: Quién pue rexistrase require_invite_text: Riquir un motivu pa rexistrase diff --git a/config/locales/simple_form.be.yml b/config/locales/simple_form.be.yml index 245c1e8528..f8000a1c81 100644 --- a/config/locales/simple_form.be.yml +++ b/config/locales/simple_form.be.yml @@ -77,13 +77,10 @@ be: warn: Схаваць адфільтраваны кантэнт за папярэджаннем з назвай фільтру form_admin_settings: activity_api_enabled: Падлік лакальна апублікаваных пастоў, актыўных карыстальнікаў і новых рэгістрацый у тыдзень - backups_retention_period: Захоўваць створаныя архівы карыстальніка адзначаную колькасць дзён. bootstrap_timeline_accounts: Гэтыя ўліковыя запісы будуць замацаваны ў топе рэкамендацый для новых карыстальнікаў. closed_registrations_message: Паказваецца, калі рэгістрацыя закрытая - content_cache_retention_period: Допісы з іншых сервераў будуць выдаляцца пасля выстаўленай колькасці дзён, калі выстаўлены станоўчы лік. Гэта можа быць незваротным. custom_css: Вы можаце прымяняць карыстальніцкія стылі ў вэб-версіі Mastodon. mascot: Замяняе ілюстрацыю ў пашыраным вэб-інтэрфейсе. - media_cache_retention_period: Спампаваныя медыя будуць выдаляцца пасля выстаўленай колькасці дзён, калі выстаўлены станоўчы лік, і спампоўвацца нанова па запыце. peers_api_enabled: Спіс даменных імён, з якімі сутыкнуўся гэты сервер у федэсвеце. Дадзеныя аб тым, ці знаходзіцеся вы з пэўным серверам у федэрацыі, не ўключаныя, ёсць толькі тое, што ваш сервер ведае пра гэта. Гэта выкарыстоўваецца сэрвісамі, якія збіраюць статыстыку па федэрацыі ў агульным сэнсе. profile_directory: Дырэкторыя профіляў змяшчае спіс усіх карыстальнікаў, якія вырашылі быць бачнымі. require_invite_text: Калі рэгістрацыя патрабуе ручнога пацвержання, зрабіце поле "Чаму вы хочаце далучыцца?" абавязковым @@ -243,7 +240,6 @@ be: backups_retention_period: Працягласць захавання архіву карыстальніка bootstrap_timeline_accounts: Заўсёды раіць гэтыя ўліковыя запісы новым карыстальнікам closed_registrations_message: Уласнае паведамленне, калі рэгістрацыя немагчымая - content_cache_retention_period: Працягласць захавання кэшу для змесціва custom_css: CSS карыстальніка mascot: Уласны маскот(спадчына) media_cache_retention_period: Працягласць захавання кэшу для медыя diff --git a/config/locales/simple_form.bg.yml b/config/locales/simple_form.bg.yml index e85e753e88..a4a2027137 100644 --- a/config/locales/simple_form.bg.yml +++ b/config/locales/simple_form.bg.yml @@ -77,13 +77,13 @@ bg: warn: Скриване на филтрираното съдържание зад предупреждение, споменавайки заглавието на филтъра form_admin_settings: activity_api_enabled: Броят на местните публикувани публикации, дейни потребители и нови регистрации в седмични кофи - backups_retention_period: Задържане на породените потребителски архиви за определения брой дни. + backups_retention_period: Потребителите имат способността да пораждат архиви от публикациите си за по-късно изтегляне. Задавайки положителна стойност, тези архиви самодейно ще се изтрият от хранилището ви след определения брой дни. bootstrap_timeline_accounts: Тези акаунти ще се закачат в горния край на препоръките за следване на нови потребители. closed_registrations_message: Показва се, когато е затворено за регистрации - content_cache_retention_period: Всички публикации и подсилвания от други сървъри ще се изтрият след определен брой дни. Някои публикации може да не се възстановят. Всички сродни отметки, любими и подсилвания също ще се загубят и невъзможно да се отмени. + content_cache_retention_period: Всички публикации от други сървъри, включително подсилвания и отговори, ще се изтрият след посочения брой дни, без да се взема предвид каквото и да е взаимодействие на местния потребител с тези публикации. Това включва публикации, които местния потребител е означил като отметки или любими. Личните споменавания между потребители от различни инстанции също ще се загубят и невъзможно да се възстановят. Употребата на тази настройка е предназначена за случаи със специално предназначение и разбива очакванията на много потребители, когато се изпълнява за употреба с общо предназначение. custom_css: Може да прилагате собствени стилове в уебверсията на Mastodon. mascot: Замества илюстрацията в разширения уеб интерфейс. - media_cache_retention_period: Изтеглените мултимедийни файлове ще се изтрият след посочения брой дни, задавайки положително число, и ще се изтеглят пак при поискване. + media_cache_retention_period: Мултимедийни файлове от публикации, направени от отдалечени потребители, се сринаха в сървъра ви. Задавайки положителна стойност, мултимедията ще се изтрие след посочения брой дни. Ако се искат мултимедийни данни след изтриването, то ще се изтегли пак, ако още е наличен източникът на съдържание. Поради ограниченията за това колко често картите за предварващ преглед на връзките анкетират сайтове на трети страни, се препоръчва да зададете тази стойност на поне 14 дни или картите за предварващ преглед на връзките няма да се обновяват при поискване преди този момент. peers_api_enabled: Списък от имена на домейни, с които сървърът се е свързал във федивселената. Тук не се включват данни за това дали федерирате с даден сървър, а само за това дали сървърът ви знае за него. Това се ползва от услуги, събиращи статистика за федерацията в общия смисъл. profile_directory: Указателят на профили вписва всички потребители, избрали да бъдат откриваеми. require_invite_text: Когато регистрацията изисква ръчно одобрение, то направете текстовото поле за това "Защо желаете да се присъедините?" по-скоро задължително, отколкото по желание @@ -243,7 +243,7 @@ bg: backups_retention_period: Период за съхранение на потребителския архив bootstrap_timeline_accounts: Винаги да се препоръчват следните акаунти на нови потребители closed_registrations_message: Съобщение при неналична регистрация - content_cache_retention_period: Период на съхранение на кеша за съдържание + content_cache_retention_period: Период на запазване на отдалечено съдържание custom_css: Персонализиран CSS mascot: Плашило талисман по избор (остаряло) media_cache_retention_period: Период на запазване на мултимедийния кеш diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml index e4bee0214c..62c1da55b5 100644 --- a/config/locales/simple_form.ca.yml +++ b/config/locales/simple_form.ca.yml @@ -77,13 +77,13 @@ ca: warn: Oculta el contingut filtrat darrere d'un avís mencionant el títol del filtre form_admin_settings: activity_api_enabled: Contador de tuts publicats localment, usuaris actius i registres nous en períodes setmanals - backups_retention_period: Manté els arxius d'usuari generats durant el nombre de dies especificats. + backups_retention_period: Els usuaris poden generar arxius de les seves publicacions per a baixar-los més endavant. Quan tingui un valor positiu, els arxius s'esborraran del vostre emmagatzematge després del nombre donat de dies. bootstrap_timeline_accounts: Aquests comptes es fixaran en la part superior de les recomanacions de seguiment dels nous usuaris. closed_registrations_message: Es mostra quan el registres estan tancats - content_cache_retention_period: Els tuts d'altres servidors se suprimiran després del nombre de dies especificat quan s'estableix un valor positiu. Això pot ser irreversible. + content_cache_retention_period: S'esborraran totes les publicacions d'altres servidors (impulsos i respostes inclosos) passats els dies indicats, sense tenir en consideració les interaccions d'usuaris locals amb aquestes publicacions. Això inclou les publicacions que un usuari local hagi marcat com a favorites. També es perdran, i no es podran recuperar, les mencions privades entre usuaris d'instàncies diferents. Aquest paràmetre està pensat per a instàncies amb un propòsit especial i trencarà les expectatives dels usuaris si s'utilitza en una instància convencional. custom_css: Pots aplicar estils personalitzats en la versió web de Mastodon. mascot: Anul·la la il·lustració en la interfície web avançada. - media_cache_retention_period: Els fitxers multimèdia descarregats s'esborraran després del nombre de dies especificat quan el valor configurat és positiu, i tornats a descarregats sota demanda. + media_cache_retention_period: El vostre servidor conserva una còpia dels fitxers multimèdia de les publicacions dels usuaris remots. Si s'indica un valor positiu, s'esborraran passats els dies indicats. Si el fitxer es torna a demanar un cop esborrat, es tornarà a baixar si el contingut origen segueix disponible. Per causa de les restriccions en la freqüència amb què es poden demanar les targetes de previsualització d'altres servidors, es recomana definir aquest valor com a mínim a 14 dies, o les targetes de previsualització no s'actualizaran a demanda abans d'aquest termini. peers_api_enabled: Una llista de noms de domini que aquest servidor ha trobat al fedivers. No inclou cap dada sobre si estàs federat amb un servidor determinat, només si el teu en sap res. La fan servir, en un sentit general, serveis que recol·lecten estadístiques sobre la federació. profile_directory: El directori de perfils llista tots els usuaris que tenen activat ser descoberts. require_invite_text: Quan el registre requereixi aprovació manual, fes que sigui obligatori en lloc d'opcional d'escriure el text de la sol·licitud d'invitació "Per què vols unir-te?" @@ -243,7 +243,7 @@ ca: backups_retention_period: Període de retenció del arxiu d'usuari bootstrap_timeline_accounts: Recomana sempre aquests comptes als nous usuaris closed_registrations_message: Missatge personalitzat quan el registre no és accessible - content_cache_retention_period: Període de retenció de la memòria cau de contingut + content_cache_retention_period: Període de retenció del contingut remot custom_css: CSS personalitzat mascot: Mascota personalitzada (llegat) media_cache_retention_period: Període de retenció del cau multimèdia diff --git a/config/locales/simple_form.cs.yml b/config/locales/simple_form.cs.yml index f91f826730..54edc4149d 100644 --- a/config/locales/simple_form.cs.yml +++ b/config/locales/simple_form.cs.yml @@ -77,13 +77,13 @@ cs: warn: Schovat filtrovaný obsah za varováním zmiňujicím název filtru form_admin_settings: activity_api_enabled: Počty lokálně zveřejnělých příspěvků, aktivních uživatelů a nových registrací v týdenních intervalech - backups_retention_period: Zachovat generované uživatelské archivy pro zadaný počet dní. + backups_retention_period: Uživatelé mají možnost vytvářet archivy svých příspěvků, které si mohou stáhnout později. Pokud je nastaveno na kladnou hodnotu, budou tyto archivy po zadaném počtu dní automaticky odstraněny z úložiště. bootstrap_timeline_accounts: Tyto účty budou připnuty na vrchol nových uživatelů podle doporučení. closed_registrations_message: Zobrazeno při zavření registrace - content_cache_retention_period: Příspěvky z jiných serverů budou odstraněny po zadaném počtu dní, pokud je nastavena kladná hodnota. To může být nevratné. + content_cache_retention_period: Všechny příspěvky z jiných serverů (včetně boostů a odpovědí) budou po uplynutí stanoveného počtu dní smazány bez ohledu na interakci místního uživatele s těmito příspěvky. To se týká i příspěvků, které místní uživatel přidal do záložek nebo oblíbených. Soukromé zmínky mezi uživateli z různých instancí budou rovněž ztraceny a nebude možné je obnovit. Použití tohoto nastavení je určeno pro instance pro speciální účely a při implementaci pro obecné použití porušuje mnohá očekávání uživatelů. custom_css: Můžete použít vlastní styly ve verzi Mastodonu. mascot: Přepíše ilustraci v pokročilém webovém rozhraní. - media_cache_retention_period: Stažené mediální soubory budou po zadaném počtu dní odstraněny, pokud je nastavena kladná hodnota, a na požádání znovu staženy. + media_cache_retention_period: Mediální soubory z příspěvků vzdálených uživatelů se ukládají do mezipaměti na vašem serveru. Pokud je nastaveno na kladnou hodnotu, budou média po zadaném počtu dní odstraněna. Pokud jsou mediální data vyžádána po jejich odstranění, budou znovu stažena, pokud je zdrojový obsah stále k dispozici. Vzhledem k omezením týkajícím se četnosti dotazů karet náhledů odkazů na weby třetích stran se doporučuje nastavit tuto hodnotu alespoň na 14 dní, jinak nebudou karty náhledů odkazů na vyžádání aktualizovány dříve. peers_api_enabled: Seznam názvů domén se kterými se tento server setkal ve fediversu. Neobsahuje žádná data o tom, zda jste federovali s daným serverem, pouze že o něm váš server ví. Toto je využíváno službami, které sbírají o federování statistiku v obecném smyslu. profile_directory: Adresář profilu obsahuje seznam všech uživatelů, kteří se přihlásili, aby mohli být nalezeni. require_invite_text: Pokud přihlášení vyžaduje ruční schválení, měl by být textový vstup „Proč se chcete připojit?“ povinný spíše než volitelný @@ -243,7 +243,7 @@ cs: backups_retention_period: Doba uchovávání archivu uživatelů bootstrap_timeline_accounts: Vždy doporučovat tyto účty novým uživatelům closed_registrations_message: Vlastní zpráva, když přihlášení není k dispozici - content_cache_retention_period: Doba uchování mezipaměti obsahu + content_cache_retention_period: Doba uchovávání vzdáleného obsahu custom_css: Vlastní CSS mascot: Vlastní maskot (zastaralé) media_cache_retention_period: Doba uchovávání mezipaměti médií diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml index 21cd1ddc0a..6b5e8787dd 100644 --- a/config/locales/simple_form.cy.yml +++ b/config/locales/simple_form.cy.yml @@ -77,13 +77,10 @@ cy: warn: Cuddiwch y cynnwys wedi'i hidlo y tu ôl i rybudd sy'n sôn am deitl yr hidlydd form_admin_settings: activity_api_enabled: Cyfrif o bostiadau a gyhoeddir yn lleol, defnyddwyr gweithredol, a chofrestriadau newydd mewn bwcedi wythnosol - backups_retention_period: Cadw archifau defnyddwyr a gynhyrchwyd am y nifer penodedig o ddyddiau. bootstrap_timeline_accounts: Bydd y cyfrifon hyn yn cael eu pinio i frig argymhellion dilynol defnyddwyr newydd. closed_registrations_message: Yn cael eu dangos pan fydd cofrestriadau wedi cau - content_cache_retention_period: Bydd postiadau o weinyddion eraill yn cael eu dileu ar ôl y nifer penodedig o ddyddiau pan fyddan nhw wedi'u gosod i werth positif. Gall nad oes modd dadwneud hyn. custom_css: Gallwch gymhwyso arddulliau cyfaddas ar fersiwn gwe Mastodon. mascot: Yn diystyru'r darlun yn y rhyngwyneb gwe uwch. - media_cache_retention_period: Bydd ffeiliau cyfryngau wedi'u llwytho i lawr yn cael eu dileu ar ôl y nifer penodedig o ddyddiau pan gânt eu gosod i werth cadarnhaol, a'u hail-lwytho i lawr ar alw. peers_api_enabled: Rhestr o enwau parth y mae'r gweinydd hwn wedi dod ar eu traws yn y ffediws. Nid oes unrhyw ddata wedi'i gynnwys yma ynghylch a ydych chi'n ffedereiddio â gweinydd penodol, dim ond bod eich gweinydd yn gwybod amdano. Defnyddir hwn gan wasanaethau sy'n casglu ystadegau ar ffedereiddio mewn ystyr cyffredinol. profile_directory: Mae'r cyfeiriadur proffil yn rhestru'r holl ddefnyddwyr sydd wedi dewis i fod yn ddarganfyddiadwy. require_invite_text: Pan fydd angen cymeradwyaeth â llaw ar gyfer cofrestriadau, gwnewch y “Pam ydych chi am ymuno?” mewnbwn testun yn orfodol yn hytrach na dewisol @@ -243,7 +240,6 @@ cy: backups_retention_period: Cyfnod cadw archif defnyddwyr bootstrap_timeline_accounts: Argymhellwch y cyfrifon hyn i ddefnyddwyr newydd bob amser closed_registrations_message: Neges bersonol pan nad yw cofrestriadau ar gael - content_cache_retention_period: Cyfnod cadw storfa cynnwys custom_css: CSS cyfaddas mascot: Mascot cyfaddas (hen) media_cache_retention_period: Cyfnod cadw storfa cyfryngau diff --git a/config/locales/simple_form.da.yml b/config/locales/simple_form.da.yml index 6c8d995bfd..c9dcd4fa83 100644 --- a/config/locales/simple_form.da.yml +++ b/config/locales/simple_form.da.yml @@ -77,13 +77,13 @@ da: warn: Skjul filtreret indhold bag en advarsel, der nævner filterets titel form_admin_settings: activity_api_enabled: Antal lokalt opslåede indlæg, aktive brugere samt nye tilmeldinger i ugentlige opdelinger - backups_retention_period: Behold genererede brugerarkiver i det angivne antal dage. + backups_retention_period: Brugere har mulighed for at generere arkiver af deres indlæg til senere downloade. Når sat til positiv værdi, vil disse arkiver automatisk blive slettet fra lagerpladsen efter det angivne antal dage. bootstrap_timeline_accounts: Disse konti fastgøres øverst på nye brugeres følg-anbefalinger. closed_registrations_message: Vises, når tilmeldinger er lukket - content_cache_retention_period: Indlæg fra andre servere slettes efter det angivne antal dage, når sat til en positiv værdi. Dette kan være irreversibelt. + content_cache_retention_period: Alle indlæg fra andre servere (herunder boosts og besvarelser) slettes efter det angivne antal dage uden hensyn til lokal brugerinteraktion med disse indlæg. Dette omfatter indlæg, hvor en lokal bruger har markeret dem som bogmærker eller favoritter. Private omtaler mellem brugere fra forskellige instanser vil også være tabt og umulige at gendanne. Brugen af denne indstilling er beregnet til særlige formål instanser og bryder mange brugerforventninger ved implementering til almindelig brug. custom_css: Man kan anvende tilpassede stilarter på Mastodon-webversionen. mascot: Tilsidesætter illustrationen i den avancerede webgrænseflade. - media_cache_retention_period: Downloadede mediefiler slettes efter det angivne antal dage, når sat til en positiv værdi, og gendownloades på forlangende. + media_cache_retention_period: Mediefiler fra indlæg oprettet af eksterne brugere er cachet på din server. Når sat til positiv værdi, slettes medier efter det angivne antal dage. Anmodes om mediedata efter de er slettet, gendownloades de, hvis kildeindholdet stadig er tilgængeligt. Grundet begrænsninger på, hvor ofte linkforhåndsvisningskort forespørger tredjeparts websteder, anbefales det at sætte denne værdi til mindst 14 dage, ellers opdateres linkforhåndsvisningskort ikke efter behov før det tidspunkt. peers_api_enabled: En liste med domænenavne, som denne server har stødt på i fediverset. Ingen data inkluderes her om, hvorvidt der fødereres med en given server, blot at din server kender til det. Dette bruges af tjenester, som indsamler generelle føderationsstatistikker. profile_directory: Profilmappen oplister alle brugere, som har valgt at kunne opdages. require_invite_text: Når tilmelding kræver manuel godkendelse, så gør “Hvorfor ønsker du at deltage?” tekstinput obligatorisk i stedet for valgfrit @@ -243,7 +243,7 @@ da: backups_retention_period: Brugerarkivs opbevaringsperiode bootstrap_timeline_accounts: Anbefal altid disse konti til nye brugere closed_registrations_message: Tilpasset besked, når tilmelding er utilgængelig - content_cache_retention_period: Indholds-cache opbevaringsperiode + content_cache_retention_period: Opbevaringsperiode for eksternt indhold custom_css: Tilpasset CSS mascot: Tilpasset maskot (ældre funktion) media_cache_retention_period: Media-cache opbevaringsperiode diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index 1d3fba7876..758d020282 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -77,13 +77,13 @@ de: warn: Den gefilterten Beitrag hinter einer Warnung, die den Filtertitel beinhaltet, ausblenden form_admin_settings: activity_api_enabled: Anzahl der wöchentlichen Beiträge, aktiven Profile und Registrierungen auf diesem Server - backups_retention_period: Behalte die Archive, die von den Benutzer*innen erstellt worden sind, für die angegebene Anzahl an Tagen. + backups_retention_period: Nutzer*innen haben die Möglichkeit, Archive ihrer Beiträge zu erstellen, die sie später herunterladen können. Wenn ein positiver Wert gesetzt ist, werden diese Archive nach der festgelegten Anzahl von Tagen automatisch aus deinem Speicher gelöscht. bootstrap_timeline_accounts: Diese Konten werden bei den Follower-Empfehlungen für neu registrierte Nutzer*innen oben angeheftet. closed_registrations_message: Wird angezeigt, wenn Registrierungen deaktiviert sind - content_cache_retention_period: Sowohl alle Beiträge als auch geteilte Beiträge von anderen Servern werden nach der angegebenen Anzahl von Tagen gelöscht. Alle zugehörigen Lesezeichen, Favoriten und geteilte Beiträge werden ebenfalls verloren gehen. Dies kann nicht mehr rückgängig gemacht werden. + content_cache_retention_period: Sämtliche Beiträge von anderen Servern (einschließlich geteilte Beiträge und Antworten) werden, unabhängig von der Interaktion der lokalen Nutzer*innen mit diesen Beiträgen, nach der festgelegten Anzahl von Tagen gelöscht. Das betrifft auch Beiträge, die von lokalen Nutzer*innen favorisiert oder als Lesezeichen gespeichert wurden. Private Erwähnungen zwischen Nutzer*innen von verschiedenen Servern werden ebenfalls verloren gehen und können nicht wiederhergestellt werden. Das Verwenden dieser Option richtet sich ausschließlich an Server für spezielle Zwecke und wird die allgemeine Nutzungserfahrung beeinträchtigen, wenn sie für den allgemeinen Gebrauch aktiviert ist. custom_css: Du kannst benutzerdefinierte Stile auf die Web-Version von Mastodon anwenden. mascot: Überschreibt die Abbildung in der erweiterten Weboberfläche. - media_cache_retention_period: Von anderen Servern übertragene Mediendateien werden nach der angegebenen Anzahl an Tagen – sofern das Feld eine positive Zahl enthält – aus dem Cache gelöscht und bei Bedarf erneut heruntergeladen. + media_cache_retention_period: Mediendateien aus Beiträgen von externen Nutzer*innen werden auf deinem Server zwischengespeichert. Wenn ein positiver Wert gesetzt ist, werden die Medien nach der festgelegten Anzahl von Tagen gelöscht. Sollten die Medien nach dem Löschvorgang wieder angefragt werden, werden sie erneut heruntergeladen, sofern der ursprüngliche Inhalt noch vorhanden ist. Es wird empfohlen, diesen Wert auf mindestens 14 Tage festzulegen, da die Häufigkeit der Abfrage von Linkvorschaukarten für Websites von Dritten begrenzt ist und die Linkvorschaukarten sonst nicht vor Ablauf dieser Zeit aktualisiert werden. peers_api_enabled: Eine Liste von Domains, die diesem Server im Fediverse begegnet sind. Hierbei werden keine Angaben darüber gemacht, ob du mit einem bestimmten Server föderierst, sondern nur, dass dein Server davon weiß. Dies wird von Diensten verwendet, die allgemein Statistiken übers Ferdiverse sammeln. profile_directory: Dieses Verzeichnis zeigt alle Profile an, die sich dafür entschieden haben, entdeckt zu werden. require_invite_text: Wenn Registrierungen eine manuelle Genehmigung erfordern, dann werden Nutzer einen Grund für ihre Registrierung angeben müssen @@ -243,7 +243,7 @@ de: backups_retention_period: Aufbewahrungsfrist für Archive bootstrap_timeline_accounts: Neuen Nutzern immer diese Konten empfehlen closed_registrations_message: Nachricht, falls Registrierungen deaktiviert sind - content_cache_retention_period: Aufbewahrungsfrist für Inhalte im Cache + content_cache_retention_period: Aufbewahrungsfrist für externe Inhalte custom_css: Eigenes CSS mascot: Benutzerdefiniertes Maskottchen (Legacy) media_cache_retention_period: Aufbewahrungsfrist für Medien im Cache diff --git a/config/locales/simple_form.el.yml b/config/locales/simple_form.el.yml index 4ffc496d02..29b9f59e14 100644 --- a/config/locales/simple_form.el.yml +++ b/config/locales/simple_form.el.yml @@ -67,13 +67,10 @@ el: warn: Απόκρυψη φιλτραρισμένου περιεχομένου πίσω από μια προειδοποίηση που αναφέρει τον τίτλο του φίλτρου form_admin_settings: activity_api_enabled: Καταμέτρηση τοπικά δημοσιευμένων δημοσιεύσεων, ενεργών χρηστών και νέων εγγραφών σε εβδομαδιαία πακέτα - backups_retention_period: Διατήρηση αρχείων χρηστών που δημιουργήθηκαν για τον καθορισμένο αριθμό ημερών. bootstrap_timeline_accounts: Αυτοί οι λογαριασμοί θα καρφιτσωθούν στην κορυφή των νέων χρηστών που ακολουθούν τις συστάσεις. closed_registrations_message: Εμφανίζεται όταν κλείνουν οι εγγραφές - content_cache_retention_period: Αναρτήσεις από άλλους διακομιστές θα διαγραφούν μετά τον καθορισμένο αριθμό ημερών όταν οριστεί μια θετική τιμή. Αυτό μπορεί να είναι μη αναστρέψιμο. custom_css: Μπορείς να εφαρμόσεις προσαρμοσμένα στυλ στην έκδοση ιστοσελίδας του Mastodon. mascot: Παρακάμπτει την εικονογραφία στην προηγμένη διεπαφή ιστού. - media_cache_retention_period: Τα ληφθέντα αρχεία πολυμέσων θα διαγραφούν μετά τον καθορισμένο αριθμό ημερών, όταν οριστεί σε θετική τιμή, και να γίνει εκ νέου λήψη κατά απαίτηση. peers_api_enabled: Μια λίστα με ονόματα τομέα που συνάντησε αυτός ο διακομιστής στο fediverse. Δεν περιλαμβάνονται δεδομένα εδώ για το αν συναλλάσσετε με ένα συγκεκριμένο διακομιστή, μόνο ότι ο διακομιστής σας το ξέρει. Χρησιμοποιείται από υπηρεσίες που συλλέγουν στατιστικά στοιχεία για την συναλλαγή με γενική έννοια. profile_directory: Ο κατάλογος προφίλ παραθέτει όλους τους χρήστες που έχουν επιλέξει να είναι ανακαλύψιμοι. require_invite_text: 'Όταν η εγγραφή απαιτεί χειροκίνητη έγκριση, κάνε το πεδίο κειμένου: «Γιατί θέλετε να συμμετάσχετε;» υποχρεωτικό αντί για προαιρετικό' @@ -224,7 +221,6 @@ el: backups_retention_period: Περίοδος αρχειοθέτησης του χρήστη bootstrap_timeline_accounts: Πρότεινε πάντα αυτούς τους λογαριασμούς σε νέους χρήστες closed_registrations_message: Προσαρμοσμένο μήνυμα όταν οι εγγραφές δεν είναι διαθέσιμες - content_cache_retention_period: Περίοδος διατήρησης προσωρινής μνήμης περιεχομένου custom_css: Προσαρμοσμένο CSS mascot: Προσαρμοσμένη μασκότ (απαρχαιωμένο) media_cache_retention_period: Περίοδος διατήρησης προσωρινής μνήμης πολυμέσων diff --git a/config/locales/simple_form.en-GB.yml b/config/locales/simple_form.en-GB.yml index e5c9b1b2b7..f4668ccada 100644 --- a/config/locales/simple_form.en-GB.yml +++ b/config/locales/simple_form.en-GB.yml @@ -77,13 +77,10 @@ en-GB: warn: Hide the filtered content behind a warning mentioning the filter's title form_admin_settings: activity_api_enabled: Counts of locally published posts, active users, and new registrations in weekly buckets - backups_retention_period: Keep generated user archives for the specified number of days. bootstrap_timeline_accounts: These accounts will be pinned to the top of new users' follow recommendations. closed_registrations_message: Displayed when sign-ups are closed - content_cache_retention_period: Posts from other servers will be deleted after the specified number of days when set to a positive value. This may be irreversible. custom_css: You can apply custom styles on the web version of Mastodon. mascot: Overrides the illustration in the advanced web interface. - media_cache_retention_period: Downloaded media files will be deleted after the specified number of days when set to a positive value, and re-downloaded on demand. peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense. profile_directory: The profile directory lists all users who have opted-in to be discoverable. require_invite_text: When sign-ups require manual approval, make the “Why do you want to join?” text input mandatory rather than optional @@ -243,7 +240,6 @@ en-GB: backups_retention_period: User archive retention period bootstrap_timeline_accounts: Always recommend these accounts to new users closed_registrations_message: Custom message when sign-ups are not available - content_cache_retention_period: Content cache retention period custom_css: Custom CSS mascot: Custom mascot (legacy) media_cache_retention_period: Media cache retention period diff --git a/config/locales/simple_form.eo.yml b/config/locales/simple_form.eo.yml index ef4641d3e7..e83f71a2cb 100644 --- a/config/locales/simple_form.eo.yml +++ b/config/locales/simple_form.eo.yml @@ -75,13 +75,10 @@ eo: warn: Kaŝi la enhavon filtritan malantaŭ averto mencianta la nomon de la filtro form_admin_settings: activity_api_enabled: Nombroj de loke publikigitaj afiŝoj, aktivaj uzantoj kaj novaj registradoj en semajnaj siteloj - backups_retention_period: Konservi generitajn uzantoarkivojn por la kvanto de tagoj. bootstrap_timeline_accounts: Ĉi tiuj kontoj pinglitas al la supro de sekvorekomendoj de novaj uzantoj. closed_registrations_message: Montrita kiam registroj fermitas - content_cache_retention_period: Mesaĝoj de aliaj serviloj forigitas post la kvanto de tagoj kiam fiksitas al pozitiva nombro. custom_css: Vi povas meti propajn stilojn en la retversio de Mastodon. mascot: Anstatauigi la ilustraĵon en la altnivela retinterfaco. - media_cache_retention_period: Elŝutitaj audovidaĵojn forigotas post la kvanto de tagoj kiam fiksitas al pozitiva nombro. peers_api_enabled: Listo de domajnaj nomoj kiujn ĉi tiu servilo renkontis en la fediverso. Neniuj datumoj estas inkluditaj ĉi tie pri ĉu vi federacias kun donita servilo, nur ke via servilo scias pri ĝi. Ĉi tio estas uzata de servoj kiuj kolektas statistikojn pri federacio en ĝenerala signifo. profile_directory: La profilujo listigas ĉiujn uzantojn kiu volonte malkovrebli. require_invite_text: Kiam registroj bezonas permanan aprobon, igi la "Kial vi volas aliĝi?" tekstoenigon deviga anstau nedeviga @@ -240,7 +237,6 @@ eo: backups_retention_period: Uzantoarkivretendauro bootstrap_timeline_accounts: Ĉiam rekomendi ĉi tiujn kontojn al novaj uzantoj closed_registrations_message: Kutima mesaĝo kiam registroj ne estas disponeblaj - content_cache_retention_period: Enhavkaŝaĵretendauro custom_css: Propa CSS mascot: Propa maskoto media_cache_retention_period: Audovidaĵkaŝaĵretendauro diff --git a/config/locales/simple_form.es-AR.yml b/config/locales/simple_form.es-AR.yml index 0111624082..cd1b681688 100644 --- a/config/locales/simple_form.es-AR.yml +++ b/config/locales/simple_form.es-AR.yml @@ -77,13 +77,13 @@ es-AR: warn: Ocultar el contenido filtrado detrás de una advertencia mencionando el título del filtro form_admin_settings: activity_api_enabled: Conteos de mensajes publicados localmente, cuentas activas y nuevos registros en tandas semanales - backups_retention_period: Conservar los archivos historiales generados por el usuario durante el número de días especificado. + backups_retention_period: Los usuarios tienen la capacidad de generar archivos historiales de sus mensajes para descargar más adelante. Cuando se establece un valor positivo, estos archivos se eliminarán automáticamente de su almacenamiento después del número especificado de días. bootstrap_timeline_accounts: Estas cuentas serán fijadas a la parte superior de las recomendaciones de cuentas a seguir para nuevos usuarios. closed_registrations_message: Mostrado cuando los registros están cerrados - content_cache_retention_period: Todos los mensajes y adhesiones de otros servidores se eliminarán después del número especificado de días. Es posible que algunos mensajes no sean recuperables. Todos los marcadores relacionados, mensajes marcados como favoritos y adhesiones también se perderán y será imposible de deshacer. + content_cache_retention_period: Todos los mensajes de otros servidores (incluyendo adhesiones y respuestas) se eliminarán después del número de días especificado, sin tener en cuenta la interacción del usuario local con esos mensajes. Esto incluye mensajes que un usuario local haya agregado a marcadores o los haya marcado como favoritos. Las menciones privadas entre usuarios de diferentes servidores también se perderán y también serán imposibles de restaurar. El uso de esta configuración está destinado a servidores de propósito especial y rompe muchas expectativas de los usuarios cuando se implementa para uso general. custom_css: Podés aplicar estilos personalizados a la versión web de Mastodon. mascot: Reemplaza la ilustración en la interface web avanzada. - media_cache_retention_period: Los archivos de medios descargados se eliminarán después del número especificado de días cuando se establezca un valor positivo, y se volverán a descargar a pedido. + media_cache_retention_period: Los archivos de medios de mensajes publicados por usuarios remotos se almacenan en la memoria caché en tu servidor. Cuando se establece un valor positivo, los medios se eliminarán después del número especificado de días. Si los datos multimedia se solicitan después de eliminarse, se volverán a descargar, si es que el contenido fuente todavía está disponible. Debido a restricciones en la frecuencia con la que las tarjetas de previsualización de enlace consultan a sitios web de terceros, se recomienda establecer este valor a, al menos, 14 días, o las tarjetas de previsualización de enlaces no se actualizarán a pedido antes de ese momento. peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el Fediverso. Acá no se incluye ningún dato sobre si federás con un servidor determinado, sólo que tu servidor lo conoce. Esto es usado por los servicios que recopilan estadísticas sobre la federación en un sentido general. profile_directory: El directorio de perfiles lista a todos los usuarios que han optado a que su cuenta pueda ser descubierta. require_invite_text: Cuando registros aprobación manual, hacé que la solicitud de invitación "¿Por qué querés unirte?" sea obligatoria, en vez de opcional @@ -243,7 +243,7 @@ es-AR: backups_retention_period: Período de retención del archivo historial del usuario bootstrap_timeline_accounts: Siempre recomendar estas cuentas a usuarios nuevos closed_registrations_message: Mensaje personalizado cuando los registros no están disponibles - content_cache_retention_period: Período de retención de la caché de contenido + content_cache_retention_period: Período de retención de contenido remoto custom_css: CSS personalizado mascot: Mascota personalizada (legado) media_cache_retention_period: Período de retención de la caché de medios diff --git a/config/locales/simple_form.es-MX.yml b/config/locales/simple_form.es-MX.yml index 28253d385b..90e223dec3 100644 --- a/config/locales/simple_form.es-MX.yml +++ b/config/locales/simple_form.es-MX.yml @@ -77,13 +77,13 @@ es-MX: warn: Ocultar el contenido filtrado detrás de una advertencia mencionando el título del filtro form_admin_settings: activity_api_enabled: Conteo de publicaciones publicadas localmente, usuarios activos, y nuevos registros en periodos semanales - backups_retention_period: Mantener los archivos de usuario generados durante el número de días especificado. + backups_retention_period: Los usuarios tienen la capacidad de generar archivos de sus mensajes para descargar más adelante. Cuando se establece un valor positivo, estos archivos se eliminarán automáticamente del almacenamiento después del número de días especificado. bootstrap_timeline_accounts: Estas cuentas aparecerán en la parte superior de las recomendaciones de los nuevos usuarios. closed_registrations_message: Mostrado cuando los registros están cerrados - content_cache_retention_period: Las publicaciones de otros servidores se eliminarán después del número especificado de días cuando se establezca un valor positivo. Esto puede ser irreversible. + content_cache_retention_period: Todas las publicaciones de otros servidores (incluso impulsos y respuestas) se eliminarán después del número de días especificado, sin tener en cuenta la interacción del usuario local con esos mensajes. Esto incluye mensajes donde un usuario local los ha marcado como marcadores o favoritos. Las menciones privadas entre usuarios de diferentes instancias también se perderán sin posibilidad de recuperación. El uso de esta configuración está destinado a instancias de propósito especial, y rompe muchas expectativas de los usuarios cuando se implementa para un uso de propósito general. custom_css: Puedes aplicar estilos personalizados a la versión web de Mastodon. mascot: Reemplaza la ilustración en la interfaz web avanzada. - media_cache_retention_period: Los archivos multimedia descargados se eliminarán después del número especificado de días cuando se establezca un valor positivo, y se redescargarán bajo demanda. + media_cache_retention_period: Los archivos multimedia de las publicaciones creadas por usuarios remotos se almacenan en caché en tu servidor. Cuando se establece un valor positivo, estos archivos se eliminarán después del número especificado de días. Si los datos multimedia se solicitan después de eliminarse, se volverán a descargar, si el contenido fuente todavía está disponible. Debido a restricciones en la frecuencia con la que las tarjetas de previsualización de enlaces realizan peticiones a sitios de terceros, se recomienda establecer este valor a al menos 14 días, o las tarjetas de previsualización de enlaces no se actualizarán bajo demanda antes de ese momento. peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el fediverso. Aquí no se incluye ningún dato sobre si usted federa con un servidor determinado, sólo que su servidor lo sabe. Esto es utilizado por los servicios que recopilan estadísticas sobre la federación en un sentido general. profile_directory: El directorio de perfiles lista a todos los usuarios que han optado por que su cuenta pueda ser descubierta. require_invite_text: Cuando los registros requieren aprobación manual, hace obligatoria la entrada de texto "¿Por qué quieres unirte?" en lugar de opcional @@ -243,7 +243,7 @@ es-MX: backups_retention_period: Período de retención del archivo de usuario bootstrap_timeline_accounts: Recomendar siempre estas cuentas a nuevos usuarios closed_registrations_message: Mensaje personalizado cuando los registros no están disponibles - content_cache_retention_period: Período de retención de caché de contenido + content_cache_retention_period: Período de retención de contenido remoto custom_css: CSS personalizado mascot: Mascota personalizada (legado) media_cache_retention_period: Período de retención de caché multimedia diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml index 008ac16073..1d75bc4234 100644 --- a/config/locales/simple_form.es.yml +++ b/config/locales/simple_form.es.yml @@ -77,13 +77,13 @@ es: warn: Ocultar el contenido filtrado detrás de una advertencia mencionando el título del filtro form_admin_settings: activity_api_enabled: Conteo de publicaciones publicadas localmente, usuarios activos y registros nuevos cada semana - backups_retention_period: Mantener los archivos de usuario generados durante el número de días especificado. + backups_retention_period: Los usuarios tienen la capacidad de generar archivos de sus mensajes para descargar más adelante. Cuando se establece un valor positivo, estos archivos se eliminarán automáticamente del almacenamiento después del número de días especificado. bootstrap_timeline_accounts: Estas cuentas aparecerán en la parte superior de las recomendaciones de los nuevos usuarios. closed_registrations_message: Mostrado cuando los registros están cerrados - content_cache_retention_period: Las publicaciones de otros servidores se eliminarán después del número especificado de días cuando se establezca un valor positivo. Esto puede ser irreversible. + content_cache_retention_period: Todas las publicaciones de otros servidores (incluso impulsos y respuestas) se eliminarán después del número de días especificado, sin tener en cuenta la interacción del usuario local con esos mensajes. Esto incluye mensajes donde un usuario local los ha marcado como marcadores o favoritos. Las menciones privadas entre usuarios de diferentes instancias también se perderán sin posibilidad de recuperación. El uso de esta configuración está destinado a instancias de propósito especial, y rompe muchas expectativas de los usuarios cuando se implementa para un uso de propósito general. custom_css: Puedes aplicar estilos personalizados a la versión web de Mastodon. mascot: Reemplaza la ilustración en la interfaz web avanzada. - media_cache_retention_period: Los archivos multimedia descargados se eliminarán después del número especificado de días cuando se establezca un valor positivo, y se redescargarán bajo demanda. + media_cache_retention_period: Los archivos multimedia de las publicaciones creadas por usuarios remotos se almacenan en caché en tu servidor. Cuando se establece un valor positivo, estos archivos se eliminarán después del número especificado de días. Si los datos multimedia se solicitan después de eliminarse, se volverán a descargar, si el contenido fuente todavía está disponible. Debido a restricciones en la frecuencia con la que las tarjetas de previsualización de enlaces realizan peticiones a sitios de terceros, se recomienda establecer este valor a al menos 14 días, o las tarjetas de previsualización de enlaces no se actualizarán bajo demanda antes de ese momento. peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el Fediverso. Aquí no se incluye ningún dato sobre si federas con un servidor determinado, solo que tu servidor lo conoce. Esto es utilizado por los servicios que recopilan estadísticas sobre la federación en un sentido general. profile_directory: El directorio de perfiles lista a todos los usuarios que han optado por que su cuenta pueda ser descubierta. require_invite_text: Cuando los registros requieren aprobación manual, hace obligatoria la entrada de texto "¿Por qué quieres unirte?" en lugar de opcional @@ -243,7 +243,7 @@ es: backups_retention_period: Período de retención del archivo de usuario bootstrap_timeline_accounts: Recomendar siempre estas cuentas a nuevos usuarios closed_registrations_message: Mensaje personalizado cuando los registros no están disponibles - content_cache_retention_period: Período de retención de caché de contenido + content_cache_retention_period: Período de retención de contenido remoto custom_css: CSS personalizado mascot: Mascota personalizada (legado) media_cache_retention_period: Período de retención de caché multimedia diff --git a/config/locales/simple_form.et.yml b/config/locales/simple_form.et.yml index 1f7d940049..b2ad4c51cf 100644 --- a/config/locales/simple_form.et.yml +++ b/config/locales/simple_form.et.yml @@ -77,13 +77,10 @@ et: warn: Varja filtreeritud sisu hoiatusega, nimetades filtri pealkirja form_admin_settings: activity_api_enabled: Kohalike postituste, aktiivsete kasutajate ja uute registreerumistr arv nädala kaupa grupeeritult - backups_retention_period: Talleta genereeritud kasutajaarhiivid määratud arv päevi. bootstrap_timeline_accounts: Need kasutajad kinnitatakse uute kasutajate jälgimissoovituste esiritta. closed_registrations_message: Kuvatakse, kui liitumised pole võimalikud - content_cache_retention_period: Teiste serverite postitused kustutatakse pärast määratud päevade arvu, kui see on seatud positiivsele väärtusele. See võib olla pöördumatu. custom_css: Kohandatud stiile on võimalik kasutada Mastodoni veebiliideses. mascot: Asendab kohandatud veebiliidese illustratsiooni. - media_cache_retention_period: Positiivse väärtuse korral kustutatakse allalaetud meediafailid määratud päevade möödudes. Vajadusel laaditakse need uuesti alla. peers_api_enabled: Domeeninimede loetelu, mida see server on Fediversumis kohanud. Mitte mingeid andmeid selle serveri födereerumise kohta antud serverite pole, vaid üksnes info, et sellest serverist ollakse teadlik. Seda kasutavad teenused, mis koguvad üldist födereerumise statistikat. profile_directory: Kasutajate kataloog kuvab nimekirja kasutajatest, kes on seda lubanud. require_invite_text: Kui liitumisi on tarvis kinnitada, oleks "Miks soovid liituda?" vastus vajalik @@ -243,7 +240,6 @@ et: backups_retention_period: Kasutajate arhiivi talletusperiood bootstrap_timeline_accounts: Alati soovita neid kontosid uutele kasutajatele closed_registrations_message: Kohandatud teade, kui liitumine pole võimalik - content_cache_retention_period: Meediapuhvri talletusperiood custom_css: Kohandatud CSS mascot: Kohandatud maskott (kunagine) media_cache_retention_period: Meediapuhvri talletusperiood diff --git a/config/locales/simple_form.eu.yml b/config/locales/simple_form.eu.yml index 5ed3b9efa1..ba4c9ebcf8 100644 --- a/config/locales/simple_form.eu.yml +++ b/config/locales/simple_form.eu.yml @@ -77,13 +77,13 @@ eu: warn: Ezkutatu iragazitako edukia iragazkiaren izenburua duen abisu batekin form_admin_settings: activity_api_enabled: Lokalki argitaratutako bidalketak, erabiltzaile aktiboak, eta izen-emateen kopuruak astero zenbatzen ditu - backups_retention_period: Mantendu sortutako erabiltzailearen artxiboa zehazturiko egun kopuruan. + backups_retention_period: Erabiltzaileek geroago deskarga dezaketen beren argitalpenen artxiboak sor ditzakete. Balio positibo bat ezartzean, artxibo hauek biltegiratzetik automatikoki ezabatuko dira zehazturiko egunen buruan. bootstrap_timeline_accounts: Kontu hauek erabiltzaile berrien jarraitzeko gomendioen goiko aldean ainguratuko dira. closed_registrations_message: Izen-ematea itxia dagoenean bistaratua - content_cache_retention_period: Balio positibo bat ezarriz gero, egun kopuru horretara iristean beste zerbitzarietako bidalketak ezabatuko dira. Hau ezin da desegin. + content_cache_retention_period: Beste zerbitzarietako argitalpen guztiak (bultzadak eta erantzunak barne) ezabatuko dira zehazturiko egunen buruan, argitalpen horiek izan ditzaketen erabiltzaile lokalaren interakzioa kontuan izanik gabe. Instantzia desberdinetako erabiltzaileen arteko aipamen pribatuak ere galdu egingo dira eta ezin izango dira berreskuratu. Ezarpen honen erabilera xede berezia duten instantziei zuzendua dago eta erabiltzaileen itxaropena hausten da orotariko erabilerarako inplementatzean. custom_css: Estilo pertsonalizatuak aplikatu ditzakezu Mastodonen web bertsioan. mascot: Web interfaze aurreratuko ilustrazioa gainidazten du. - media_cache_retention_period: Balio positibo bat ezarriz gero, egun kopuru horretara iristean beste zerbitzarietatik deskargatutako multimedia fitxategiak ezabatuko dira. Ondoren, eskatu ahala deskargatuko dira berriz. + media_cache_retention_period: Multimedia-fitxategiak dituzten urruneko erabiltzaileen argitalpenak zure zerbitzarian gordetzen dira cachean. Balio positiboa ezartzean, multimedia zehazturiko egunen buruan ezabatuko da. Multimedia-datuak eskatzen badira ezabatu ostean, berriro deskargatuko dira, iturburuko edukia oraindik erabilgarri badago. Estekaren aurrebistako txartelek hirugarrenen guneei zenbatetan dei diezaieketen mugatzen dieten murrizketak direla eta, balio honi, gutxienez, 14 egunen balioa ezartzea gomendatzen da, bestela, esteken aurrebistako txartelak ez dira eguneratuko eskatu ahala denbora horren aurretik. peers_api_enabled: Zerbitzari honek fedibertsoan ikusi dituen zerbitzarien domeinu-izenen zerrenda. Ez da daturik ematen zerbitzari jakin batekin federatzearen ala ez federatzearen inguruan, zerbitzariak haien berri duela soilik. Federazioari buruzko estatistika orokorrak biltzen dituzten zerbitzuek erabiltzen dute hau. profile_directory: Profilen direktorioan ikusgai egotea aukeratu duten erabiltzaile guztiak zerrendatzen dira. require_invite_text: Izen emateak eskuz onartu behar direnean, "Zergatik elkartu nahi duzu?" testu sarrera derrigorrezko bezala ezarri, ez hautazko @@ -243,7 +243,7 @@ eu: backups_retention_period: Erabiltzailearen artxiboa gordetzeko epea bootstrap_timeline_accounts: Gomendatu beti kontu hauek erabiltzaile berriei closed_registrations_message: Izen-emateak itxita daudenerako mezu pertsonalizatua - content_cache_retention_period: Edukiaren cache-a atxikitzeko epea + content_cache_retention_period: Urruneko edukiaren atxikipen-aldia custom_css: CSS pertsonalizatua mascot: Maskota pertsonalizatua (zaharkitua) media_cache_retention_period: Multimediaren cachea atxikitzeko epea diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml index 03f1875451..dd1c56e3bd 100644 --- a/config/locales/simple_form.fa.yml +++ b/config/locales/simple_form.fa.yml @@ -75,13 +75,10 @@ fa: warn: نهفتن محتوای پالوده پشت هشداری که به عنوان پالایه اشاره می‌کند form_admin_settings: activity_api_enabled: تعداد بوق‌های منتشرهٔ محلی، کاربران فعال، و کاربران تازه در هر هفته - backups_retention_period: نگه داشتن بایگانی‌های کاربری برای روزهای مشخّص شده. bootstrap_timeline_accounts: سنجاق کردنThese accounts will be pinned to the top of new users' follow recommendations. closed_registrations_message: نمایش داده هنگام بسته بودن ثبت‌نام‌ها - content_cache_retention_period: همهٔ فرسته‌ها و تقویت‌ها از دیگر کارسازها پس از روزهای نشخّص حذف خواهند شد. ممکن است برخی فرسته‌ها قابل بازیابی نباشند. همهٔ نشانک‌ها، پسندها و تقویت‌ها نیز از دست خواهند رفت و قابل بازگشت نخواهند بود. custom_css: می‌توانیدروی نگارش وب ماستودون سبک‌های سفارشی اعمال کنید. mascot: نقش میانای وب پیش‌رفته را پایمال می‌کند. - media_cache_retention_period: اگر به مقدار مثبتی تنظیم شود، پرونده‌های رسانهٔ بارگرفته پس از روزهای مشخّص شده حذف خواهند شد و هنگام درخواست دوباره بارگرفته می‌شوند. peers_api_enabled: فهرستی از نام‌های دامنه‌ای که این کارساز در فدیورس با آن مواجه شده است. هیچ اطلاعاتی در مورد اینکه آیا شما با یک کارساز داده شده متعهد هستید، در اینجا گنجانده نشده است، فقط کارساز شما در مورد آن می‌داند. این توسط خدماتی استفاده می‌شود که آمار مربوط به فدراسیون را به معنای کلی جمع‌آوری می‌کنند. profile_directory: شاخهٔ نمایه، همهٔ کاربرانی که کشف‌پذیری را برگزیده‌اند سیاهه می‌کند. require_invite_text: زمانی که نام‌نویسی ها نیازمند تایید دستی است، متن «چرا می‌خواهید بپیوندید؟» بخش درخواست دعوت را به جای اختیاری، اجباری کنید @@ -225,7 +222,6 @@ fa: backups_retention_period: دورهٔ نگه‌داری بایگانی کاربری bootstrap_timeline_accounts: پیشنهاد همیشگی این حساب‌ها به کاربران جدید closed_registrations_message: پیام سفارشی هنگام در دسترس نبودن ثبت‌نام‌ها - content_cache_retention_period: دورهٔ نگه‌داری انبارهٔ محتوا custom_css: سبک CSS سفارشی mascot: نشان سفارشی (قدیمی) media_cache_retention_period: دورهٔ نگه‌داری انبارهٔ رسانه diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml index c3fbd43720..c342dde33e 100644 --- a/config/locales/simple_form.fi.yml +++ b/config/locales/simple_form.fi.yml @@ -77,13 +77,10 @@ fi: warn: Piilota suodatettu sisältö varoituksen taakse, jossa mainitaan suodattimen nimi form_admin_settings: activity_api_enabled: Paikallisesti julkaistujen julkaisujen, aktiivisten käyttäjien ja rekisteröitymisten viikoittainen määrä - backups_retention_period: Säilytä luodut arkistot määritetyn määrän päiviä. bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuosituslistojen alkuun. closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu - content_cache_retention_period: Kaikki julkaisut ja tehostukset muilta palvelimilta poistetaan, kun määritelty määrä päiviä on kulunut. Osaa julkaisuista voi olla mahdoton palauttaa. Kaikki julkaisuihin liittyvät kirjanmerkit, suosikit ja tehostukset menetetään, eikä niitä voi palauttaa. custom_css: Voit käyttää mukautettuja tyylejä Mastodonin verkkoversiossa. mascot: Ohittaa kuvituksen edistyneessä selainkäyttöliittymässä. - media_cache_retention_period: Ladatut mediatiedostot poistetaan määritetyn määrän päiviä jälkeen, kun arvo on positiivinen ja ladataan uudelleen pyynnöstä. peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, oletko liitossa tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja federoinnista yleisellä tasolla. profile_directory: Profiilihakemisto lueteloi kaikki käyttäjät, jotka ovat ilmoittaneet olevansa löydettävissä. require_invite_text: Kun rekisteröityminen vaatii manuaalisen hyväksynnän, tee ”Miksi haluat liittyä?” -tekstikentästä pakollinen vapaaehtoisen sijaan @@ -243,7 +240,7 @@ fi: backups_retention_period: Käyttäjän arkiston säilytysaika bootstrap_timeline_accounts: Suosittele aina näitä tilejä uusille käyttäjille closed_registrations_message: Mukautettu viesti, kun rekisteröityminen ei ole saatavilla - content_cache_retention_period: Sisällön välimuistin säilytysaika + content_cache_retention_period: Etäsisällön säilytysaika custom_css: Mukautettu CSS mascot: Mukautettu maskotti (vanhentunut ominaisuus) media_cache_retention_period: Mediasisältövälimuistin säilytysaika diff --git a/config/locales/simple_form.fo.yml b/config/locales/simple_form.fo.yml index 599e79ea2f..c7c0033225 100644 --- a/config/locales/simple_form.fo.yml +++ b/config/locales/simple_form.fo.yml @@ -77,13 +77,13 @@ fo: warn: Fjal filtreraða innihaldið aftan fyri eina ávaring, sum nevnir heitið á filtrinum form_admin_settings: activity_api_enabled: Tal av lokalt útgivnum postum, virknum brúkarum og nýggjum skrásetingum býtt vikuliga - backups_retention_period: Varðveit gjørd brúkarasøvn í ásetta talið av døgum. + backups_retention_period: Brúkarar hava møguleika at gera trygdaravrit av teirra postum, sum tey kunnu taka niður seinni. Tá hetta er sett til eitt virði størri enn 0, so verða hesi trygdaravrit strikaði av sær sjálvum frá tínar goymslu eftir ásetta talið av døgum. bootstrap_timeline_accounts: Hesar kontur verða festar ovast á listanum yvir brúkarar, sum tey nýggju verða mælt til at fylgja. closed_registrations_message: Víst tá stongt er fyri tilmeldingum - content_cache_retention_period: Postar frá øðrum ambætarum verða strikaðir eftir ásetta talið av døgum, tá hetta er sett til eitt positivt virði. Hetta kann møguliga ikki broytast. + content_cache_retention_period: Allir postar frá øðrum ambætarum (íroknað stimbranir og svar) verða strikaði eftir ásetta talið av døgum, óansæð hvussu lokalir brúkarar hava samvirkað við hesar postar. Hetta fevnir eisini um postar, sum lokalir brúkarar hava bókamerkt ella yndismerkt. Privatar umrøður millum brúkarar frá ymiskum ambætarum verða eisini burturmistar og ómøguligar at endurskapa. Brúk av hesi stillingini er einans hugsað til serligar støður og oyðileggur nógv, sum brúkarar vænta av einum vanligum ambætara. custom_css: Tú kanst seta títt egna snið upp í net-útgávuni av Mastodon. mascot: Skúgvar til viks myndprýðingina í framkomna vev-markamótinum. - media_cache_retention_period: Miðlafílur, sum eru tiknar niður, verða strikaðar eftir ásetta talið av døgum, tá hetta er sett til eitt positivt virði, og takast niður umaftur eftir ynski. + media_cache_retention_period: Miðlafílur frá postum, sum fjarbrúkarar hava gjørt, verða goymdir á tínum ambætara. Tá hetta er sett til eitt virði størri enn 0, so verða miðlafílurnar strikaðar eftir ásetta talið av døgum. Um miðladátur verða umbidnar eftir at tær eru strikaðar, verða tær tiknar innaftur á ambætaran, um keldutilfarið enn er tøkt. Vegna avmarkingar á hvussu ofta undanvísingarkort til leinki spyrja triðjapartsstøð, so verður mælt til at seta hetta virðið til í minsta lagi 14 dagar. Annars verða umbønir um dagføringar av undanvísingarkortum til leinki ikki gjørdar áðrenn hetta. peers_api_enabled: Ein listi við navnaøkjum, sum hesin ambætarin er komin framat í fediversinum. Ongar dátur eru tiknar við her um tú er sameind/ur við ein givnan ambætara, einans at tín ambætari veit um hann. Hetta verður brúkt av tænastum, sum gera hagtøl um sameining yvirhøvur. profile_directory: Vangaskráin listar allar brúkarar, sum hava valt at kunna uppdagast. require_invite_text: Tá tilmeldingar krevja serskilda góðkenning, set so "Hví vil tú vera við?" tekstateigin til at vera kravdan heldur enn valfrían @@ -243,7 +243,7 @@ fo: backups_retention_period: Hvussu leingi verða brúkarasøvn goymd bootstrap_timeline_accounts: Mæl altíð nýggjum brúkarum at fylgja hesar kontur closed_registrations_message: Serskild boð, tá tað ikki er møguligt at tilmelda seg - content_cache_retention_period: Tíðarskeið, har innihaldgoymslan verður varðveitt + content_cache_retention_period: Tíðarskeið fyri varðveiðslu av fjartilfari custom_css: Serskilt CSS mascot: Serskildur maskottur (arvur) media_cache_retention_period: Tíðarskeið, har miðlagoymslur verða varðveittar diff --git a/config/locales/simple_form.fr-CA.yml b/config/locales/simple_form.fr-CA.yml index 823929c550..4b3f53e222 100644 --- a/config/locales/simple_form.fr-CA.yml +++ b/config/locales/simple_form.fr-CA.yml @@ -77,13 +77,10 @@ fr-CA: warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre form_admin_settings: activity_api_enabled: Nombre de messages publiés localement, de comptes actifs et de nouvelles inscriptions par tranche hebdomadaire - backups_retention_period: Conserve les archives générées par l'utilisateur selon le nombre de jours spécifié. bootstrap_timeline_accounts: Ces comptes seront épinglés en tête de liste des recommandations pour les nouveaux utilisateurs. closed_registrations_message: Affiché lorsque les inscriptions sont fermées - content_cache_retention_period: Les publications depuis d'autres serveurs seront supprimées après un nombre de jours spécifiés lorsque défini sur une valeur positive. Cela peut être irréversible. custom_css: Vous pouvez appliquer des styles personnalisés sur la version Web de Mastodon. mascot: Remplace l'illustration dans l'interface Web avancée. - media_cache_retention_period: Les fichiers multimédias téléchargés seront supprimés après le nombre de jours spécifiés lorsque la valeur est positive, et seront téléchargés à nouveau sur demande. peers_api_enabled: Une liste de noms de domaine que ce serveur a rencontrés dans le fédiverse. Aucune donnée indiquant si vous vous fédérez ou non avec un serveur particulier n'est incluse ici, seulement l'information que votre serveur connaît un autre serveur. Cette option est utilisée par les services qui collectent des statistiques sur la fédération en général. profile_directory: L'annuaire des profils répertorie tous les utilisateurs qui ont opté pour être découverts. require_invite_text: Lorsque les inscriptions nécessitent une approbation manuelle, rendre le texte de l’invitation "Pourquoi voulez-vous vous inscrire ?" obligatoire plutôt que facultatif @@ -243,7 +240,6 @@ fr-CA: backups_retention_period: Période d'archivage utilisateur bootstrap_timeline_accounts: Toujours recommander ces comptes aux nouveaux utilisateurs closed_registrations_message: Message personnalisé lorsque les inscriptions ne sont pas disponibles - content_cache_retention_period: Durée de rétention du contenu dans le cache custom_css: CSS personnalisé mascot: Mascotte personnalisée (héritée) media_cache_retention_period: Durée de rétention des médias dans le cache diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml index 4c8de1b20d..476f197f41 100644 --- a/config/locales/simple_form.fr.yml +++ b/config/locales/simple_form.fr.yml @@ -77,13 +77,10 @@ fr: warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre form_admin_settings: activity_api_enabled: Nombre de messages publiés localement, de comptes actifs et de nouvelles inscriptions par tranche hebdomadaire - backups_retention_period: Conserve les archives générées par l'utilisateur selon le nombre de jours spécifié. bootstrap_timeline_accounts: Ces comptes seront épinglés en tête de liste des recommandations pour les nouveaux utilisateurs. closed_registrations_message: Affiché lorsque les inscriptions sont fermées - content_cache_retention_period: Lorsque la valeur est positive, les messages publiés depuis d'autres serveurs seront supprimés après le nombre de jours défini. Cela peut être irréversible. custom_css: Vous pouvez appliquer des styles personnalisés sur la version Web de Mastodon. mascot: Remplace l'illustration dans l'interface Web avancée. - media_cache_retention_period: Lorsque la valeur est positive, les fichiers multimédias téléchargés seront supprimés après le nombre de jours défini et pourront être à nouveau téléchargés sur demande. peers_api_enabled: Une liste de noms de domaine que ce serveur a rencontrés dans le fédiverse. Aucune donnée indiquant si vous vous fédérez ou non avec un serveur particulier n'est incluse ici, seulement l'information que votre serveur connaît un autre serveur. Cette option est utilisée par les services qui collectent des statistiques sur la fédération en général. profile_directory: L'annuaire des profils répertorie tous les comptes qui choisi d'être découvrables. require_invite_text: Lorsque les inscriptions nécessitent une approbation manuelle, rendre le texte de l’invitation "Pourquoi voulez-vous vous inscrire ?" obligatoire plutôt que facultatif @@ -243,7 +240,6 @@ fr: backups_retention_period: Durée de rétention des archives utilisateur bootstrap_timeline_accounts: Toujours recommander ces comptes aux nouveaux⋅elles utilisateur⋅rice⋅s closed_registrations_message: Message personnalisé lorsque les inscriptions ne sont pas disponibles - content_cache_retention_period: Durée de rétention du contenu dans le cache custom_css: CSS personnalisé mascot: Mascotte personnalisée (héritée) media_cache_retention_period: Durée de rétention des médias dans le cache diff --git a/config/locales/simple_form.fy.yml b/config/locales/simple_form.fy.yml index e2e40f04dd..fa1633c901 100644 --- a/config/locales/simple_form.fy.yml +++ b/config/locales/simple_form.fy.yml @@ -77,13 +77,10 @@ fy: warn: Ferstopje de filtere ynhâld efter in warskôging, mei de titel fan it filter as warskôgingstekst form_admin_settings: activity_api_enabled: Tal lokaal publisearre artikelen, aktive brûkers en nije registraasjes yn wyklikse werjefte - backups_retention_period: De oanmakke brûkersargiven foar it opjûne oantal dagen behâlde. bootstrap_timeline_accounts: Dizze accounts wurde boppe oan de oanrekommandaasjes oan nije brûkers toand. Meardere brûkersnammen troch komma’s skiede. closed_registrations_message: Werjûn wannear’t registraasje fan nije accounts útskeakele is - content_cache_retention_period: 'Berjochten fan oare servers wurde nei it opjûne oantal dagen fuortsmiten. Let op: Dit is definityf.' custom_css: Jo kinne oanpaste CSS tapasse op de webferzje fan dizze Mastodon-server. mascot: Oerskriuwt de yllustraasje yn de avansearre webomjouwing. - media_cache_retention_period: Mediabestannen dy’t fan oare servers download binne wurde nei it opjûne oantal dagen fuortsmiten en wurde op fersyk opnij download. peers_api_enabled: In list mei domeinnammen, dêr’t dizze server yn fediverse kontakt hân mei hat. Hjir wurdt gjin data dield, oft jo mei in bepaalde server federearrest, mar alinnich, dat jo server dat wit. Dit wurdt foar tsjinsten brûkt, dy’t statistiken oer federaasje yn algemiene sin sammelet. profile_directory: De brûkersgids befettet in list fan alle brûkers dy¥t derfoar keazen hawwe om ûntdekt wurde te kinnen. require_invite_text: Meitsje it ynfoljen fan ‘Wêrom wolle jo jo hjir registrearje?’ ferplicht yn stee fan opsjoneel, wannear’t registraasjes hânmjittich goedkard wurde moatte @@ -243,7 +240,6 @@ fy: backups_retention_period: Bewartermyn brûkersargyf bootstrap_timeline_accounts: Accounts dy’t altyd oan nije brûkers oanrekommandearre wurde closed_registrations_message: Oanpast berjocht wannear registraasje útskeakele is - content_cache_retention_period: Bewartermyn berjochtebuffer custom_css: Oanpaste CSS mascot: Oanpaste maskotte (legacy) media_cache_retention_period: Bewartermyn mediabuffer diff --git a/config/locales/simple_form.gd.yml b/config/locales/simple_form.gd.yml index 168e7168ed..8a36f73dc1 100644 --- a/config/locales/simple_form.gd.yml +++ b/config/locales/simple_form.gd.yml @@ -77,13 +77,10 @@ gd: warn: Falaich an t-susbaint chriathraichte air cùlaibh rabhaidh a dh’innseas tiotal na criathraige form_admin_settings: activity_api_enabled: Cunntasan nam postaichean a chaidh fhoillseachadh gu h-ionadail, nan cleachdaichean gnìomhach ’s nan clàraidhean ùra an am bucaidean seachdaineil - backups_retention_period: Cùm na tasg-lannan a chaidh a ghintinn dhan luchd-cleachdaidh rè an àireamh de làithean a shònraich thu. bootstrap_timeline_accounts: Thèid na cunntasan seo a phrìneachadh air bàrr nam molaidhean leantainn dhan luchd-cleachdaidh ùr. closed_registrations_message: Thèid seo a shealltainn nuair a bhios an clàradh dùinte - content_cache_retention_period: Thèid gach post is brosnachadh o fhrithealaichean eile a sguabadh às às dèidh an àireamh de làithean a shònraicheas tu. Dh’fhaoidte nach gabh a h-uile post aiseag. Thèid gach comharran-lìn, annsachd is brosnachadh co-cheangailte riutha air chall cuideachd agus cha ghabh sin a neo-dhèanamh. custom_css: "’S urrainn dhut stoidhlean gnàthaichte a chur an sàs air an tionndadh-lìn de Mhastodon." mascot: Tar-àithnidh seo an sgead-dhealbh san eadar-aghaidh-lìn adhartach. - media_cache_retention_period: Thèid na faidhlichean meadhain air an luchdadh a-nuas a sguabadh às às dèidh an àireamh de làithean a shònraich thu nuair a bhios luach dearbh air agus an ath-luachdadh nuair a thèid an iarraidh an uairsin. peers_api_enabled: Seo liosta de dh’ainmean àrainne ris an do thachair am frithealaiche seo sa cho-shaoghal. Chan eil dàta sam bith ’ga ghabhail a-staigh an-seo mu a bheil thu co-naisgte ri frithealaiche sònraichte gus nach eil ach dìreach gu bheil am frithealaiche agad eòlach air. Thèid seo a chleachdadh le seirbheisean a chruinnicheas stadastaireachd air a’ cho-nasgadh san fharsaingeachd. profile_directory: Seallaidh eòlaire nam pròifil liosta dhen luchd-cleachdaidh a dh’aontaich gun gabh an rùrachadh. require_invite_text: Nuair a bhios aontachadh a làimh riatanach dhan chlàradh, dèan an raon teacsa “Carson a bu mhiann leat ballrachd fhaighinn?” riatanach seach roghainneil @@ -243,7 +240,6 @@ gd: backups_retention_period: Ùine glèidhidh aig tasg-lannan an luchd-cleachdaidh bootstrap_timeline_accounts: Mol na cunntasan seo do chleachdaichean ùra an-còmhnaidh closed_registrations_message: Teachdaireachd ghnàthaichte nuair nach eil clàradh ri fhaighinn - content_cache_retention_period: Ùine glèidhidh aig tasgadan na susbainte custom_css: CSS gnàthaichte mascot: Suaichnean gnàthaichte (dìleabach) media_cache_retention_period: Ùine glèidhidh aig tasgadan nam meadhanan diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml index ffb12d31bc..bd7c850df4 100644 --- a/config/locales/simple_form.gl.yml +++ b/config/locales/simple_form.gl.yml @@ -77,13 +77,10 @@ gl: warn: Agochar o contido filtrado tras un aviso que conteña o nome do filtro form_admin_settings: activity_api_enabled: Conta do número de publicacións locais, usuarias activas, e novos rexistros en acumulados semanais - backups_retention_period: Gardar os arquivos xerados pola usuaria durante o número de días indicado. bootstrap_timeline_accounts: Estas contas aparecerán fixas na parte superior das recomendacións para as usuarias. closed_registrations_message: Móstrase cando non se admiten novas usuarias - content_cache_retention_period: As publicacións desde outros servidores serán eliminadas despois do número de días indicados ao poñer un valor positivo. É unha acción irreversible. custom_css: Podes aplicar deseños personalizados na versión web de Mastodon. mascot: Sobrescribe a ilustración na interface web avanzada. - media_cache_retention_period: Os ficheiros multimedia descargados serán eliminados despois do número de días indicado ao establecer un valor positivo, e voltos a descargar baixo petición. peers_api_enabled: Unha lista dos nomes de dominio que este servidor atopou no fediverso. Non se inclúen aquí datos acerca de se estás a federar con eles ou non, só que o teu servidor os recoñeceu. Ten utilidade para servizos que recollen estatísticas acerca da federación nun amplo senso. profile_directory: O directorio de perfís inclúe a tódalas usuarias que optaron por ser descubribles. require_invite_text: Cando os rexistros requiren aprobación manual, facer que o texto "Por que te queres rexistrar?" do convite sexa obrigatorio en lugar de optativo @@ -243,7 +240,6 @@ gl: backups_retention_period: Período de retención do arquivo da usuaria bootstrap_timeline_accounts: Recomendar sempre estas contas ás novas usuarias closed_registrations_message: Mensaxe personalizada para cando o rexistro está pechado - content_cache_retention_period: Período de retención da caché do contido custom_css: CSS personalizado mascot: Mascota propia (herdado) media_cache_retention_period: Período de retención da caché multimedia diff --git a/config/locales/simple_form.he.yml b/config/locales/simple_form.he.yml index 4f2611666a..b07ed8b8b5 100644 --- a/config/locales/simple_form.he.yml +++ b/config/locales/simple_form.he.yml @@ -77,13 +77,10 @@ he: warn: הסתר את התוכן המסונן מאחורי אזהרה עם כותרת המסנן form_admin_settings: activity_api_enabled: מספר ההודעות שפורסמו מקומית, משתמשים פעילים, והרשמות חדשות בדליים שבועיים - backups_retention_period: לשמור ארכיון משתמש שנוצר למשך מספר הימים המצוין. bootstrap_timeline_accounts: חשבונות אלו יוצמדו לראש רשימת המלצות המעקב של משתמשים חדשים. closed_registrations_message: להציג כאשר הרשמות חדשות אינן מאופשרות - content_cache_retention_period: הודעות משרתים אחרים ימחקו אחרי מספר הימים המצוין כאשר מצוין מספר חיובי. פעולה זו אינה הפיכה. custom_css: ניתן לבחור ערכות סגנון אישיות בגרסת הדפדפן של מסטודון. mascot: בחירת ציור למנשק הווב המתקדם. - media_cache_retention_period: קבצי מדיה שהורדו ימחקו אחרי מספר הימים שיצוינו אם נבחר מספר חיובי, או-אז יורדו שוב מחדש בהתאם לצורך. peers_api_enabled: רשימת השרתים ששרת זה פגש בפדיוורס. לא כולל מידע לגבי קשר ישיר עם שרת נתון, אלא רק שידוע לשרת זה על קיומו. מידע זה משמש שירותים האוספים סטטיסטיקות כלליות על הפדרציה. profile_directory: ספריית הפרופילים מציגה ברשימה את כל המשתמשים שביקשו להיות ניתנים לגילוי. require_invite_text: כאשר הרשמות דורשות אישור ידני, הפיכת טקסט ה"מדוע את/ה רוצה להצטרף" להכרחי במקום אופציונלי @@ -243,7 +240,7 @@ he: backups_retention_period: תקופת השמירה של ארכיון המשתמש bootstrap_timeline_accounts: המלצה על חשבונות אלה למשתמשים חדשים closed_registrations_message: הודעה מיוחדת כשההרשמה לא מאופשרת - content_cache_retention_period: תקופת שמירת מטמון תוכן + content_cache_retention_period: תקופת השמירה על תוכן חיצוני custom_css: CSS בהתאמה אישית mascot: סמל השרת (ישן) media_cache_retention_period: תקופת שמירת מטמון מדיה diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml index 242c863274..e2040cafd8 100644 --- a/config/locales/simple_form.hu.yml +++ b/config/locales/simple_form.hu.yml @@ -77,13 +77,13 @@ hu: warn: A szűrt tartalom a szűrő címét említő figyelmeztetés mögé rejtése form_admin_settings: activity_api_enabled: Helyi bejegyzések, aktív felhasználók és új regisztrációk száma heti bontásban - backups_retention_period: Az előállított felhasználói archívumok megtartása a megadott napokig. + backups_retention_period: A felhasználók archívumokat állíthatnak elő a bejegyzéseikből, hogy később letöltsék azokat. Ha pozitív értékre van állítva, akkor a megadott számú nap után automatikusan törölve lesznek a tárhelyedről. bootstrap_timeline_accounts: Ezek a fiókok ki lesznek tűzve az új felhasználók követési javaslatainak élére. closed_registrations_message: Akkor jelenik meg, amikor a regisztráció le van zárva - content_cache_retention_period: A más kiszolgálókról származó bejegyzések megadott számú nap után törölve lesznek, ha pozitív értékre van állítva. Ez lehet, hogy nem fordítható vissza. + content_cache_retention_period: Minden más kiszolgálóról származó bejegyzés (megtolásokkal és válaszokkal együtt) törölve lesz a megadott számú nap elteltével, függetlenül a helyi felhasználók ezekkel a bejegyzésekkel történő interakcióitól. Ebben azok a bejegyzések is benne vannak, melyeket a helyi felhasználó könyvjelzőzött vagy kedvencnek jelölt. A különböző kiszolgálók felhasználói közötti privát üzenetek is el fognak veszni visszaállíthatatlanul. Ennek a beállításnak a használata különleges felhasználási esetekre javasolt, mert számos felhasználói elvárás fog eltörni, ha általános céllal használják. custom_css: A Mastodon webes verziójában használhatsz egyéni stílusokat. mascot: Felülbírálja a speciális webes felületen található illusztrációt. - media_cache_retention_period: A letöltött médiafájlok megadott számú nap után törölve lesznek, ha pozitív értékre van állítva, és igény szerint újból le lesznek töltve. + media_cache_retention_period: A távoli felhasználók bejegyzéseinek médiatartalmait a kiszolgálód gyorsítótárazza. Ha pozitív értékre állítják, ezek a médiatartalmak a megadott számú nap után törölve lesznek. Ha a médiát újra lekérik, miután törlődött, újra le fogjuk tölteni, ha az eredeti még elérhető. A hivatkozások előnézeti kártyáinak harmadik fél weboldalai felé történő hivatkozásaira alkalmazott megkötései miatt javasolt, hogy ezt az értéket legalább 14 napra állítsuk, ellenkező esetben a hivatkozások előnézeti kártyái szükség esetén nem fognak tudni frissülni ezen idő előtt. peers_api_enabled: Azon domainek listája, melyekkel ez a kiszolgáló találkozott a fediverzumban. Nem csatolunk adatot arról, hogy föderált kapcsolatban vagy-e az adott kiszolgálóval, csak arról, hogy a kiszolgálód tud a másikról. Ezt olyan szolgáltatások használják, melyek általában a föderációról készítenek statisztikákat. profile_directory: A profilok jegyzéke minden olyan felhasználót felsorol, akik engedélyezték a felfedezhetőségüket. require_invite_text: Ha a regisztrációhoz manuális jóváhagyásra van szükség, akkor a „Miért akarsz csatlakozni?” válasz kitöltése legyen kötelező, és ne opcionális @@ -243,7 +243,7 @@ hu: backups_retention_period: Felhasználói archívum megtartási időszaka bootstrap_timeline_accounts: Mindig javasoljuk ezeket a fiókokat az új felhasználók számára closed_registrations_message: A feliratkozáskor megjelenő egyéni üzenet nem érhető el - content_cache_retention_period: Tartalom-gyorsítótár megtartási időszaka + content_cache_retention_period: Távoli tartalmak megtartási időszaka custom_css: Egyéni CSS mascot: Egyéni kabala (örökölt) media_cache_retention_period: Média-gyorsítótár megtartási időszaka diff --git a/config/locales/simple_form.id.yml b/config/locales/simple_form.id.yml index 8b9e74406a..856f312eda 100644 --- a/config/locales/simple_form.id.yml +++ b/config/locales/simple_form.id.yml @@ -63,13 +63,10 @@ id: hide: Sembunyikan konten yang disaring, seperti itu tidak ada warn: Sembunyikan konten yang disaring di belakang sebuah peringatan menyebutkan judul saringan form_admin_settings: - backups_retention_period: Simpan arsip pengguna yang dibuat untuk jumlah hari yang ditetapkan. bootstrap_timeline_accounts: Akun ini akan disematkan di atas rekomendasi ikut pengguna baru. closed_registrations_message: Ditampilkan ketika pendaftaran ditutup - content_cache_retention_period: Kiriman dari server lain akan dihapus setelah jumlah hari yang ditentukan jika nilai positif ditetapkan. Ini mungkin tidak dapat diurungkan. custom_css: Anda dapat menerapkan gaya kustom di versi web Mastodon. mascot: Menimpa ilustrasi di antarmuka web tingkat lanjut. - media_cache_retention_period: File media yang diunduh akan dihapus setelah beberapa hari yang ditentukan ketika ditetapkan ke nilai yang positif, dan diunduh ulang pada permintaan. profile_directory: Direktori profil mendaftarka semua pengguna yang ingin untuk dapat ditemukan. require_invite_text: Ketika pendaftaran membutuhkan persetujuan manual, buat masukan teks "Mengapa Anda ingin bergabung?" dibutuhkan daripada opsional site_contact_email: Bagaimana orang dapat menghubungi Anda untuk kebutuhan hukum atau dukungan. @@ -216,7 +213,6 @@ id: backups_retention_period: Rentang retensi arsip pengguna bootstrap_timeline_accounts: Selalu rekomendasikan akun ini ke pengguna baru closed_registrations_message: Pesan kustom ketika pendaftaran tidak tersedia - content_cache_retention_period: Rentang retensi tembolok konten custom_css: CSS kustom mascot: Maskot kustom (lawas) media_cache_retention_period: Rentang retensi tembolok media diff --git a/config/locales/simple_form.ie.yml b/config/locales/simple_form.ie.yml index e142617fcc..e482bd828c 100644 --- a/config/locales/simple_form.ie.yml +++ b/config/locales/simple_form.ie.yml @@ -77,13 +77,10 @@ ie: warn: Celar li contenete filtrat detra un avise mentionant li titul del filtre form_admin_settings: activity_api_enabled: Númeres de postas publicat localmen, activ usatores, e nov adhesiones in periodes semanal - backups_retention_period: Mantener usator-generat archives por li specificat quantitá de dies. bootstrap_timeline_accounts: Ti-ci contos va esser pinglat al parte superiori del recomandationes por nov usatores. closed_registrations_message: Monstrat quande adhesiones es cludet - content_cache_retention_period: Omni postas e boosts de altri servitores va esser deletet pos li specificat quantitá de dies. Quelc postas fórsan va esser ínrestaurabil. Omni pertinent marcatores, favorites e boosts anc va esser perdit e ínpossibil a restaurar. custom_css: On posse aplicar customisat stiles al web-version de Mastodon. mascot: Substitue li ilustration in li avansat interfacie web. - media_cache_retention_period: Descargat files de media va esser deletet pos li specificat quantitá de dies quande li valore es positiv, e re-descargat sur demanda. peers_api_enabled: Un liste de nómines de dominia queles ti-ci servitor ha incontrat in li fediverse. Ci null data es includet pri ca tu confedera con un cert servitor o ne; it indica solmen que tui servitor conosse it. Usat per servicies colectent general statisticas pri federation. profile_directory: Li profilarium monstra omni usatores volent esser decovribil. require_invite_text: Quande registrationes besona manual aprobation, fa que li textu "Pro quo tu vole registrar te?" es obligatori vice facultativ @@ -243,7 +240,6 @@ ie: backups_retention_period: Periode de retener archives de usator bootstrap_timeline_accounts: Sempre recomandar ti-ci contos a nov usatores closed_registrations_message: Customisat missage quande registration ne disponibil - content_cache_retention_period: Periode de retention por cachat contenete custom_css: Custom CSS mascot: Customisat mascot (hereditat) media_cache_retention_period: Periode de retention por cachat medie diff --git a/config/locales/simple_form.io.yml b/config/locales/simple_form.io.yml index 57a2aeb64d..81f298249e 100644 --- a/config/locales/simple_form.io.yml +++ b/config/locales/simple_form.io.yml @@ -75,13 +75,10 @@ io: warn: Celez filtrita kontenajo dop avert quo montras titulo di filtrilo form_admin_settings: activity_api_enabled: Quanto de lokale publikigita posti, aktiva uzanti e nova registri, donita semanope - backups_retention_period: Retenez igita uzantoarkivi por la diiquanto. bootstrap_timeline_accounts: Ca konti pinglagesos a super sequorekomendi di nova uzanti. closed_registrations_message: Montresas kande registradi klozesas - content_cache_retention_period: Omna posti e repeti de altra servili efacesos pos la specigita nombro de dii. Kelka posti forsan ne esos restaurebla. Omna relata libromarki, favoriziti e repeti anke esos perdita e neposible restaurota. custom_css: Vu povas pozar kustumizita staili en retverso di Mastodon. mascot: Remplas montreso en avanca retintervizajo. - media_cache_retention_period: Deschargita mediifaili efacesos pos la diiquanto kande fixesas a positiva nombro, e rideschargesas irgatempe. peers_api_enabled: Listo di domeni quin ca servilo trovis en la fediverso. Nula informo inkluzesas hike pri ka vu federas kun partikulara servilo, nur ke vua servilo savas pri lo. Co es uzata da enti qui kolektas statistiki pri federeso generale. profile_directory: La profilcheflisto montras omna uzanti quo voluntale volas esar deskovrebla. require_invite_text: Kande registradi bezonas manuala aprobo, ol kauzigas "Por quo vu volas juntas?" textoenpozo esar obliganta @@ -239,7 +236,6 @@ io: backups_retention_period: Uzantoarkivretendurtempo bootstrap_timeline_accounts: Sempre rekomendez ca konti a nova uzanti closed_registrations_message: Kustumizita mesajo kande registradi ne esas disponebla - content_cache_retention_period: Kontenajmemorajretendurtempo custom_css: Kustumizita CSS mascot: Kustumizita reprezentimajo (oldo) media_cache_retention_period: Mediimemorajretendurtempo diff --git a/config/locales/simple_form.is.yml b/config/locales/simple_form.is.yml index cae9bbed5f..a2c437a325 100644 --- a/config/locales/simple_form.is.yml +++ b/config/locales/simple_form.is.yml @@ -77,13 +77,11 @@ is: warn: Fela síað efni á bakvið aðvörun sem tekur fram titil síunnar form_admin_settings: activity_api_enabled: Fjöldi staðværra stöðufærslna, virkra notenda og nýskráninga í vikulegum skömmtum - backups_retention_period: Halda safni notandans í tiltekinn fjölda daga. + backups_retention_period: Notendur hafa kost á að útbúa safnskrár með færslunum sínum til að sækja svo síðar. Þegar þetta er stillt á jákvætt gildi, verður þessum safnskrám eytt sjáfkrafa eftir þeim tiltekna fjölda daga. bootstrap_timeline_accounts: Þessir notendaaðgangar verða festir efst í meðmælum til nýrra notenda um að fylgjast með þeim. closed_registrations_message: Birtist þegar lokað er á nýskráningar - content_cache_retention_period: Færslum af öðrum netþjónum verður eytt eftir tiltekinn fjölda daga þegar þetta er jákvætt gildi. Þetta gæti verið óafturkallanleg aðgerð. custom_css: Þú getur virkjað sérsniðna stíla í vefútgáfu Mastodon. mascot: Þetta tekyr yfir myndskreytinguna í ítarlega vefviðmótinu. - media_cache_retention_period: Sóttu myndefni verður eytt eftir tiltekinn fjölda daga þegar þetta er jákvætt gildi og síðan sótt aftur eftir þörfum. peers_api_enabled: Listi yfir þau lénaheiti sem þessi netþjónn hefur rekist á í skýjasambandinu. Engin gögn eru hér sem gefa til kynna hvort þú sért í sambandi við tiltekinn netþjón, bara að netþjónninn þinn viti um hann. Þetta er notað af þjónustum sem safna tölfræði um skýjasambönd á almennan hátt. profile_directory: Notendamappan telur upp alla þá notendur sem hafa valið að vera uppgötvanlegir. require_invite_text: Þegar nýskráningar krefjast handvirks samþykkis, þá skal gera textann í “Hvers vegna viltu taka þátt?” að kröfu en ekki valkvæðan @@ -243,7 +241,7 @@ is: backups_retention_period: Tímalengd sem safni notandans er haldið eftir bootstrap_timeline_accounts: Alltaf mæla með þessum notendaaðgöngum fyrir nýja notendur closed_registrations_message: Sérsniðin skilaboð þegar ekki er hægt að nýskrá - content_cache_retention_period: Tímalengd sem haldið er í biðminni + content_cache_retention_period: Tímabil sem á að geyma fjartengt efni custom_css: Sérsniðið CSS mascot: Sérsniðið gæludýr (eldra) media_cache_retention_period: Tímalengd sem myndefni haldið diff --git a/config/locales/simple_form.it.yml b/config/locales/simple_form.it.yml index bf294a48c6..5c0e6aa4e8 100644 --- a/config/locales/simple_form.it.yml +++ b/config/locales/simple_form.it.yml @@ -77,13 +77,13 @@ it: warn: Nascondi il contenuto filtrato e mostra invece un avviso, citando il titolo del filtro form_admin_settings: activity_api_enabled: Conteggi di post pubblicati localmente, utenti attivi e nuove registrazioni in gruppi settimanali - backups_retention_period: Conserva gli archivi utente generati per il numero di giorni specificato. + backups_retention_period: Gli utenti hanno la possibilità di generare archivi dei propri post da scaricare successivamente. Se impostati su un valore positivo, questi archivi verranno automaticamente eliminati dallo spazio di archiviazione dopo il numero di giorni specificato. bootstrap_timeline_accounts: Questi account verranno aggiunti in cima ai consigli da seguire dei nuovi utenti. closed_registrations_message: Visualizzato alla chiusura delle iscrizioni - content_cache_retention_period: I post da altri server verranno eliminati dopo il numero di giorni specificato se impostato su un valore positivo. Questo potrebbe essere irreversibile. + content_cache_retention_period: Tutti i post da altri server (inclusi booster e risposte) verranno eliminati dopo il numero specificato di giorni, senza tener conto di eventuali interazioni con gli utenti locali con tali post. Questo include i post in cui un utente locale ha contrassegnato come segnalibri o preferiti. Anche le menzioni private tra utenti di diverse istanze andranno perse e impossibile da ripristinare. L'uso di questa impostazione è inteso per casi di scopo speciale e rompe molte aspettative dell'utente quando implementato per uso generale. custom_css: È possibile applicare stili personalizzati sulla versione web di Mastodon. mascot: Sostituisce l'illustrazione nell'interfaccia web avanzata. - media_cache_retention_period: I file multimediali scaricati verranno eliminati dopo il numero di giorni specificato se impostati su un valore positivo e scaricati nuovamente su richiesta. + media_cache_retention_period: I file multimediali da post fatti da utenti remoti sono memorizzati nella cache sul tuo server. Quando impostato a un valore positivo, i media verranno eliminati dopo il numero specificato di giorni. Se i dati multimediali sono richiesti dopo che sono stati eliminati, saranno nuovamente scaricati, se il contenuto sorgente è ancora disponibile. A causa di restrizioni su quanto spesso link anteprima carte sondaggio siti di terze parti, si consiglia di impostare questo valore ad almeno 14 giorni, o le schede di anteprima link non saranno aggiornate su richiesta prima di quel tempo. peers_api_enabled: Un elenco di nomi di dominio che questo server ha incontrato nel fediverse. Qui non sono inclusi dati sul fatto se si federano con un dato server, solo che il server ne è a conoscenza. Questo viene utilizzato dai servizi che raccolgono statistiche sulla federazione in senso generale. profile_directory: La directory del profilo elenca tutti gli utenti che hanno acconsentito ad essere individuabili. require_invite_text: 'Quando le iscrizioni richiedono l''approvazione manuale, rendi la domanda: "Perché vuoi unirti?" obbligatoria anziché facoltativa' @@ -243,7 +243,7 @@ it: backups_retention_period: Periodo di conservazione dell'archivio utente bootstrap_timeline_accounts: Consiglia sempre questi account ai nuovi utenti closed_registrations_message: Messaggio personalizzato quando le iscrizioni non sono disponibili - content_cache_retention_period: Periodo di conservazione della cache dei contenuti + content_cache_retention_period: Periodo di ritenzione del contenuto remoto custom_css: Personalizza CSS mascot: Personalizza mascotte (legacy) media_cache_retention_period: Periodo di conservazione della cache multimediale diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 81615c1344..5e35bc14c0 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -77,13 +77,10 @@ ja: warn: フィルタに一致した投稿を非表示にし、フィルタのタイトルを含む警告を表示します form_admin_settings: activity_api_enabled: 週単位でローカルで公開された投稿数、アクティブユーザー数、新規登録者数を表示します - backups_retention_period: 生成されたユーザーのアーカイブを指定した日数の間保持します。 bootstrap_timeline_accounts: これらのアカウントは、新しいユーザー向けのおすすめユーザーの一番上にピン留めされます。 closed_registrations_message: アカウント作成を停止している時に表示されます - content_cache_retention_period: 指定した日数が経過した他のサーバーの投稿とブーストを削除します。削除された投稿は再取得できない場合があります。削除された投稿についたブックマークやお気に入り、ブーストも失われ、元に戻せません。 custom_css: ウェブ版のMastodonでカスタムスタイルを適用できます。 mascot: 上級者向けWebインターフェースのイラストを上書きします。 - media_cache_retention_period: 正の値に設定されている場合、ダウンロードされたメディアファイルは指定された日数の後に削除され、リクエストに応じて再ダウンロードされます。 peers_api_enabled: このサーバーが Fediverse で遭遇したドメイン名のリストです。このサーバーが知っているだけで、特定のサーバーと連合しているかのデータは含まれません。これは一般的に Fediverse に関する統計情報を収集するサービスによって使用されます。 profile_directory: ディレクトリには、掲載する設定をしたすべてのユーザーが一覧表示されます。 require_invite_text: アカウント登録が承認制の場合、登録の際の申請事由の入力を必須にします @@ -243,7 +240,6 @@ ja: backups_retention_period: ユーザーアーカイブの保持期間 bootstrap_timeline_accounts: おすすめユーザーに常に表示するアカウント closed_registrations_message: アカウント作成を停止している時のカスタムメッセージ - content_cache_retention_period: コンテンツキャッシュの保持期間 custom_css: カスタムCSS mascot: カスタムマスコット(レガシー) media_cache_retention_period: メディアキャッシュの保持期間 diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index 790bcd061b..6ab4e03222 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -77,13 +77,10 @@ ko: warn: 필터 제목을 언급하는 경고 뒤에 걸러진 내용을 숨기기 form_admin_settings: activity_api_enabled: 주별 로컬에 게시된 글, 활성 사용자 및 새로운 가입자 수 - backups_retention_period: 생성된 사용자 아카이브를 며칠동안 저장할 지. bootstrap_timeline_accounts: 이 계정들은 팔로우 추천 목록 상단에 고정됩니다. closed_registrations_message: 새 가입을 차단했을 때 표시됩니다 - content_cache_retention_period: 다른 서버의 게시물과 부스트들은 지정한 일수가 지나면 삭제될 것입니다. 몇몇 게시물들은 복구가 불가능할 것입니다. 관련된 북마크, 좋아요, 부스트 또한 잃어버릴 것이며 취소도 할 수 없습니다. custom_css: 사용자 지정 스타일을 웹 버전의 마스토돈에 지정할 수 있습니다. mascot: 고급 웹 인터페이스의 그림을 대체합니다. - media_cache_retention_period: 양수로 설정된 경우 다운로드된 미디어 파일들은 지정된 일수가 지나면 삭제될 것이고 필요할 때 다시 다운로드 될 것입니다. peers_api_enabled: 이 서버가 연합우주에서 만났던 서버들에 대한 도메인 네임의 목록입니다. 해당 서버와 어떤 연합을 했는지에 대한 정보는 전혀 포함되지 않고, 단순히 그 서버를 알고 있는지에 대한 것입니다. 이것은 일반적으로 연합에 대한 통계를 수집할 때 사용됩니다. profile_directory: 프로필 책자는 발견되기를 희망하는 모든 사람들의 목록을 나열합니다. require_invite_text: 가입이 수동 승인을 필요로 할 때, "왜 가입하려고 하나요?" 항목을 선택사항으로 두는 것보다는 필수로 두는 것이 낫습니다 @@ -243,7 +240,6 @@ ko: backups_retention_period: 사용자 아카이브 유지 기한 bootstrap_timeline_accounts: 새로운 사용자들에게 추천할 계정들 closed_registrations_message: 가입이 불가능 할 때의 사용자 지정 메시지 - content_cache_retention_period: 콘텐츠 캐시 유지 기한 custom_css: 사용자 정의 CSS mascot: 사용자 정의 마스코트 (legacy) media_cache_retention_period: 미디어 캐시 유지 기한 diff --git a/config/locales/simple_form.ku.yml b/config/locales/simple_form.ku.yml index aa8501bf24..0c4f872131 100644 --- a/config/locales/simple_form.ku.yml +++ b/config/locales/simple_form.ku.yml @@ -65,13 +65,10 @@ ku: hide: Naveroka parzûnkirî bi tevahî veşêre, mîna ku ew tune be tevbigere warn: Naveroka parzûnkirî li pişt hişyariyek ku sernavê parzûnê qal dike veşêre form_admin_settings: - backups_retention_period: Arşîvên bikarhênerên çêkirî ji bo rojên diyarkirî tomar bike. bootstrap_timeline_accounts: Ev ajimêr wê di pêşnîyarên şopandina bikarhênerên nû de werin derzîkirin. closed_registrations_message: Dema ku tomarkirin girtî bin têne xuyakirin - content_cache_retention_period: Şandiyên ji rajekarên din wê piştî çend rojên diyarkirî dema ku li ser nirxek erênî were danîn werin jêbirin. Dibe ku ev bê veger be. custom_css: Tu dikarî awayên kesane li ser guhertoya malperê ya Mastodon bicîh bikî. mascot: Îlustrasyona navrûyê webê yê pêşketî bêbandor dike. - media_cache_retention_period: Pelên medyayê yên daxistî wê piştî çend rojên diyarkirî dema ku li ser nirxek erênî were danîn werin jêbirin, û li gorî daxwazê ​​ji nû ve werin daxistin. profile_directory: Pelrêça profîlê hemû bikarhênerên keşfbûnê hilbijartine lîste dike. require_invite_text: Gava ku tomarkirin pêdiviya pejirandina destan dike, Têketina nivîsê "Tu çima dixwazî beşdar bibî?" Bike sereke ji devla vebijêrkî site_contact_email: Mirov dikarin ji bo pirsên qanûnî yan jî yên piştgiriyê çawa xwe digihînin te. @@ -218,7 +215,6 @@ ku: backups_retention_period: Serdema tomarkirina arşîva bikarhêner bootstrap_timeline_accounts: Van ajimêran ji bikarhênerên nû re pêşniyar bike closed_registrations_message: Peyama kesane dema ku tomarkirin peyda nebin - content_cache_retention_period: Serdema tomarkirina bîrdanka naverokê custom_css: CSS a kesanekirî mascot: Mascot a kesanekirî (legacy) media_cache_retention_period: Serdema tomarkirina bîrdanka medyayê diff --git a/config/locales/simple_form.lad.yml b/config/locales/simple_form.lad.yml index 75113be18b..cef58e4601 100644 --- a/config/locales/simple_form.lad.yml +++ b/config/locales/simple_form.lad.yml @@ -77,13 +77,10 @@ lad: warn: Eskonde el kontenido filtrado detras de una avertensya enmentando el titolo del filtro form_admin_settings: activity_api_enabled: Numero de publikasyones publikadas lokalmente, utilizadores activos i enrejistrasyones muevas kada semana - backups_retention_period: Manten las dosyas de utilizador djeneradas durante el numero de diyas espesifikado. bootstrap_timeline_accounts: Estos kuentos apareseran en la parte superior de las rekomendasiones de los muevos utilizadores. closed_registrations_message: Amostrado kuando las enrejistrasyones estan serrados - content_cache_retention_period: Las publikasyones de otros sirvidores se supremiran dempues del numero espesifikado de diyas kuando se establezka una valuta pozitiva. Esto puede ser irreversivle. custom_css: Puedes aplikar estilos personalizados a la version web de Mastodon. mascot: Reemplaza la ilustrasyon en la enterfaz web avanzada. - media_cache_retention_period: Las dosyas de multimedia abashadas se supremiran dempues del numero espesifikado de diyas kuando se establezka una valuta pozitiva, i se reabasharan basho demanda. peers_api_enabled: Una lista de nombres de domeno ke este sirvidor tiene topado en el Fediverso. Aki no se inkluye dingun dato sovre si federas kon un sirvidor determinado, solo ke tu sirvidor lo konese. Esto es utilizado por los servisyos ke rekopilan estatistikas sovre la federasyon en un senso djeneral. profile_directory: El katalogo de profiles lista a todos los utilizadores ke tienen optado por ke sus kuento pueda ser deskuvierto. require_invite_text: Kuando las enrejistrasyones rekieren achetasyon manuala, faze obligatoria la entrada de teksto "Por ke keres unirte?" en lugar de ser opsyonal @@ -243,7 +240,6 @@ lad: backups_retention_period: Periodo de retensyon de la dosya de utilizador bootstrap_timeline_accounts: Rekomenda siempre estos kuentos a muevos utilizadores closed_registrations_message: Mesaj personalizado kuando las enrejistrasyones no estan desponivles - content_cache_retention_period: Periodo de retensyon de kashe de kontenido custom_css: CSS personalizado mascot: Maskota personalizada (legado) media_cache_retention_period: Periodo de retensyon de kashe multimedia diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index 5431ea1b10..00485fc873 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -74,7 +74,6 @@ lt: warn: Slėpti filtruojamą turinį po įspėjimu, paminint filtro pavadinimą form_admin_settings: activity_api_enabled: Vietinių paskelbtų įrašų, aktyvių naudotojų ir naujų registracijų skaičiai kas savaitę - backups_retention_period: Laikyti sukurtus naudotojų archyvus nurodytą dienų skaičių. peers_api_enabled: Domenų pavadinimų sąrašas, su kuriais šis serveris susidūrė fediverse. Čia nėra duomenų apie tai, ar tu bendrauji su tam tikru serveriu, tik apie tai, kad tavo serveris apie jį žino. Tai naudojama tarnybose, kurios renka federacijos statistiką bendrąja prasme. site_contact_email: Kaip žmonės gali su tavimi susisiekti teisiniais ar pagalbos užklausimais. site_contact_username: Kaip žmonės gali tave pasiekti Mastodon. @@ -146,7 +145,6 @@ lt: form_admin_settings: activity_api_enabled: Skelbti suvestinį statistiką apie naudotojų veiklą per API bootstrap_timeline_accounts: Visada rekomenduoti šias paskyras naujiems naudotojams - content_cache_retention_period: Turinio talpyklos išlaikymo laikotarpis custom_css: Pasirinktinis CSS mascot: Pasirinktinis talismanas (pasenęs) registrations_mode: Kas gali užsiregistruoti diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml index 002761065d..711484b642 100644 --- a/config/locales/simple_form.lv.yml +++ b/config/locales/simple_form.lv.yml @@ -77,13 +77,10 @@ lv: warn: Paslēp filtrēto saturu aiz brīdinājuma, kurā minēts filtra nosaukums form_admin_settings: activity_api_enabled: Vietēji publicēto ziņu, aktīvo lietotāju un jauno reģistrāciju skaits nedēļas kopās - backups_retention_period: Saglabā ģenerētos lietotāju arhīvus norādīto dienu skaitā. bootstrap_timeline_accounts: Šie konti tiks piesprausti jauno lietotāju ieteikumu augšdaļā. closed_registrations_message: Tiek rādīts, kad reģistrēšanās ir slēgta - content_cache_retention_period: Ziņas no citiem serveriem tiks dzēstas pēc norādītā dienu skaita, ja ir iestatīta pozitīva vērtība. Tas var būt neatgriezeniski. custom_css: Vari lietot pielāgotus stilus Mastodon tīmekļa versijā. mascot: Ignorē ilustrāciju uzlabotajā tīmekļa saskarnē. - media_cache_retention_period: Lejupielādētie multivides faili tiks dzēsti pēc norādītā dienu skaita, kad tie būs iestatīti uz pozitīvu vērtību, un pēc pieprasījuma tiks lejupielādēti atkārtoti. peers_api_enabled: Domēna vārdu saraksts, ar kuriem šis serveris ir saskāries fediversā. Šeit nav iekļauti dati par to, vai tu veic federāciju ar noteiktu serveri, tikai tavs serveris par to zina. To izmanto dienesti, kas apkopo statistiku par federāciju vispārīgā nozīmē. profile_directory: Profilu direktorijā ir uzskaitīti visi lietotāji, kuri ir izvēlējušies būt atklājami. require_invite_text: 'Ja pierakstīšanai nepieciešama manuāla apstiprināšana, izdari tā, lai teksta: “Kāpēc vēlaties pievienoties?” ievade ir obligāta, nevis opcionāla' @@ -242,7 +239,6 @@ lv: backups_retention_period: Lietotāja arhīva glabāšanas periods bootstrap_timeline_accounts: Vienmēr iesaki šos kontus jaunajiem lietotājiem closed_registrations_message: Pielāgots ziņojums, ja reģistrēšanās nav pieejama - content_cache_retention_period: Satura arhīva glabāšanas periods custom_css: Pielāgots CSS mascot: Pielāgots talismans (mantots) media_cache_retention_period: Multivides kešatmiņas saglabāšanas periods diff --git a/config/locales/simple_form.ms.yml b/config/locales/simple_form.ms.yml index 9e9931cc3e..ae375149eb 100644 --- a/config/locales/simple_form.ms.yml +++ b/config/locales/simple_form.ms.yml @@ -75,13 +75,10 @@ ms: warn: Sembunyikan kandungan yang ditapis di sebalik amaran yang menyebut tajuk penapis form_admin_settings: activity_api_enabled: Kiraan siaran tempatan yang diterbitkan, pengguna aktif dan pendaftaran baharu dalam baldi mingguan - backups_retention_period: Simpan arkib pengguna yang dijana untuk bilangan hari yang ditentukan. bootstrap_timeline_accounts: Akaun ini akan disematkan pada bahagian atas cadangan ikutan pengguna baharu. closed_registrations_message: Dipaparkan semasa pendaftaran ditutup - content_cache_retention_period: Semua pos dan rangsangan daripada server lain akan dipadamkan selepas bilangan hari yang ditentukan. Sesetengah siaran mungkin tidak boleh dipulihkan. Semua penanda halaman, kegemaran dan rangsangan yang berkaitan juga akan hilang dan mustahil untuk dibuat asal. custom_css: Anda boleh menggunakan gaya tersuai pada versi web Mastodon. mascot: Mengatasi ilustrasi dalam antara muka web lanjutan. - media_cache_retention_period: Fail media yang dimuat turun akan dipadamkan selepas bilangan hari yang ditetapkan apabila ditetapkan kepada nilai positif dan dimuat turun semula atas permintaan. peers_api_enabled: Senarai nama domain yang pernah ditemui oleh server ini dalam fediverse. Tiada data disertakan di sini tentang sama ada anda bersekutu dengan server tertentu, cuma server anda mengetahuinya. Ini digunakan oleh perkhidmatan yang mengumpul statistik mengenai persekutuan dalam pengertian umum. profile_directory: Direktori profil menyenaraikan semua pengguna yang telah mengikut serta untuk ditemui. require_invite_text: Apabila pendaftaran memerlukan kelulusan manual, buat "Mengapa anda mahu menyertai?" input teks wajib dan bukannya pilihan @@ -240,7 +237,6 @@ ms: backups_retention_period: Tempoh pengekalan arkib pengguna bootstrap_timeline_accounts: Sentiasa mengesyorkan akaun ini kepada pengguna baharu closed_registrations_message: Mesej tersuai apabila pendaftaran tidak tersedia - content_cache_retention_period: Tempoh pengekalan cache kandungan custom_css: CSS tersuai mascot: Maskot tersuai (warisan) media_cache_retention_period: Tempoh pengekalan cache media diff --git a/config/locales/simple_form.my.yml b/config/locales/simple_form.my.yml index 4f8a39782a..20c862ab27 100644 --- a/config/locales/simple_form.my.yml +++ b/config/locales/simple_form.my.yml @@ -75,13 +75,10 @@ my: warn: စစ်ထုတ်မှုခေါင်းစဉ်ကိုဖော်ပြသည့်သတိပေးချက်နောက်တွင် စစ်ထုတ်ထားသောအကြောင်းအရာကို ဖျောက်ထားပါ form_admin_settings: activity_api_enabled: အပတ်စဉ် စာရင်းများတွင် ဒေသတွင်းတင်ထားသောပို့စ်များ၊ လက်ရှိအသုံးပြုသူများနှင့် စာရင်းသွင်းမှုအသစ်များ - backups_retention_period: သတ်မှတ်ထားသော ရက်အရေအတွက်အလိုက် အသုံးပြုသူမှတ်တမ်းများကို သိမ်းဆည်းပါ။ bootstrap_timeline_accounts: ဤအကောင့်များကို အသုံးပြုသူအသစ်များ၏ စောင့်ကြည့်မှု အကြံပြုချက်များ၏ထိပ်ဆုံးတွင် ပင်ချိတ်ထားပါမည်။ closed_registrations_message: အကောင့်ဖွင့်ခြင်းများကို ပိတ်ထားသည့်အခါတွင် ပြသထားသည် - content_cache_retention_period: သတ်မှတ်ထားသောရက်များပြီးနောက် အခြားဆာဗာများမှ ပို့စ်များကို ဖျက်လိုက်ပါမည်။ ပြန်လည်ပြင်ဆင်၍မရပါ။ custom_css: Mastodon ဝဘ်ဗားရှင်းတွင် စိတ်ကြိုက်စတိုင်များကို အသုံးပြုနိုင်ပါသည်။ mascot: အဆင့်မြင့် ဝဘ်ပုံစံတွင်တွင် ရုပ်ပုံဖြင့်ဖော်ပြထားသည်။ - media_cache_retention_period: သတ်မှတ်ထားသောရက်များပြီးနောက် ဒေါင်းလုဒ်လုပ်ထားသော မီဒီယာဖိုင်များကို ဖျက်လိုက်ပါမည်။ တောင်းဆိုပါက ပြန်လည်ဒေါင်းလုဒ် လုပ်ခွင့်ရှိသည်။ peers_api_enabled: ဤဆာဗာမှတွေ့ရသော ဖက်ဒီနယ်ပယ်ပေါင်းစုံရှိ ဒိုမိန်းအမည်များစာရင်း။ ဖက်ဒီနယ်ပယ်များမှာ သင်အသုံးပြုနေသည့်ဆာဗာနှင့် ပေါင်းစပ်ခြင်းရှိသည်ဖြစ်စေ၊ မရှိသည်ဖြစ်စေ ဤနေရာတွင် အချက်အလက်များကို မပြသထားပါ။ ယေဘုယျအားဖြင့် ဖက်ဒရယ်ဆိုင်ရာ စာရင်းအင်းများစုဆောင်းသည့် ဝန်ဆောင်မှုကိုသာ အသုံးပြုထားသည်။ profile_directory: ပရိုဖိုင်လမ်းညွှန်တွင် ရှာဖွေ‌နိုင်သည့်အသုံးပြုသူအားလုံးကို စာရင်းပြုစုထားသည်။ require_invite_text: အကောင့်ဖွင့်ရာတွင် လူကိုယ်တိုင်ခွင့်ပြုချက်လိုအပ်သောအခါ “ဘာကြောင့်ပါဝင်ချင်သလဲ” ဟုလုပ်ပါ။ စိတ်ကြိုက်ရွေးချယ်မည့်အစား စာသားထည့်သွင်းရန်မဖြစ်မနေထည့်သွင်းပါ။ @@ -240,7 +237,6 @@ my: backups_retention_period: အသုံးပြုသူ၏ မှတ်တမ်းကာလ bootstrap_timeline_accounts: ဤအကောင့်များကို အသုံးပြုသူအသစ်များအတွက် အကြံပြုပေးပါ closed_registrations_message: အကောင့်ဖွင့်ခြင်းများ မရတော့သောအခါ စိတ်ကြိုက်မက်ဆေ့ချ်ပို့ခြင်း - content_cache_retention_period: အကြောင်းအရာ ကက်ရှ်ထိန်းသိမ်းသည့်ကာလ custom_css: စိတ်ကြိုက်ပြုလုပ်ထားသော CSS mascot: စိတ်ကြိုက်ပြုလုပ်ထားသော mascot (legacy) media_cache_retention_period: မီဒီယာကက်ရှ် ထိန်းသိမ်းသည့်ကာလ diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml index 2f2107b13c..3b10053196 100644 --- a/config/locales/simple_form.nl.yml +++ b/config/locales/simple_form.nl.yml @@ -77,13 +77,13 @@ nl: warn: Verberg de gefilterde inhoud achter een waarschuwing, met de titel van het filter als waarschuwingstekst form_admin_settings: activity_api_enabled: Aantallen lokaal gepubliceerde berichten, actieve gebruikers en nieuwe registraties per week - backups_retention_period: De aangemaakte gebruikersarchieven voor het opgegeven aantal dagen behouden. + backups_retention_period: Gebruikers hebben de mogelijkheid om archieven van hun berichten te genereren om later te downloaden. Indien ingesteld op een positieve waarde, worden deze archieven automatisch verwijderd uit jouw opslag na het opgegeven aantal dagen. bootstrap_timeline_accounts: Deze accounts worden bovenaan de aanbevelingen aan nieuwe gebruikers getoond. Meerdere gebruikersnamen met komma's scheiden. closed_registrations_message: Weergegeven wanneer registratie van nieuwe accounts is uitgeschakeld - content_cache_retention_period: Alle berichten van andere servers worden na het opgegeven aantal dagen verwijderd. Deze berichten kunnen daarna hoogstwaarschijnlijk niet meer worden hersteld. Alle gerelateerde bladwijzers, favorieten en boosts worden eveneens onomkeerbaar verwijderd. + content_cache_retention_period: Alle berichten van andere servers (inclusief boosts en reacties) worden verwijderd na het opgegeven aantal dagen, ongeacht enige lokale gebruikersinteractie met die berichten. Dit betreft ook berichten die een lokale gebruiker aan diens bladwijzers heeft toegevoegd of als favoriet heeft gemarkeerd. Privéberichten tussen gebruikers van verschillende servers gaan ook verloren en zijn onmogelijk te herstellen. Het gebruik van deze instelling is bedoeld voor servers die een speciaal doel dienen en overtreedt veel gebruikersverwachtingen wanneer deze voor algemeen gebruik wordt geïmplementeerd. custom_css: Je kunt aangepaste CSS toepassen op de webversie van deze Mastodon-server. mascot: Overschrijft de illustratie in de geavanceerde webomgeving. - media_cache_retention_period: Mediabestanden die van andere servers zijn gedownload worden na het opgegeven aantal dagen verwijderd en worden op verzoek opnieuw gedownload. + media_cache_retention_period: Mediabestanden van berichten van externe gebruikers worden op jouw server in de cache opgeslagen. Indien ingesteld op een positieve waarde, worden media verwijderd na het opgegeven aantal dagen. Als de mediagegevens worden opgevraagd nadat ze zijn verwijderd, worden ze opnieuw gedownload wanneer de originele inhoud nog steeds beschikbaar is. Vanwege beperkingen op hoe vaak linkvoorbeelden sites van derden raadplegen, wordt aanbevolen om deze waarde in te stellen op ten minste 14 dagen. Anders worden linkvoorbeelden niet op aanvraag bijgewerkt. peers_api_enabled: Een lijst met domeinnamen die deze server heeft aangetroffen in de fediverse. Er zijn hier geen gegevens inbegrepen over de vraag of je verbonden bent met een bepaalde server, alleen dat je server er van weet. Dit wordt gebruikt door diensten die statistieken over de federatie in algemene zin verzamelen. profile_directory: De gebruikersgids bevat een lijst van alle gebruikers die ervoor gekozen hebben om ontdekt te kunnen worden. require_invite_text: Maak het invullen van "Waarom wil je je hier registreren?" verplicht in plaats van optioneel, wanneer registraties handmatig moeten worden goedgekeurd @@ -243,7 +243,7 @@ nl: backups_retention_period: Bewaartermijn gebruikersarchief bootstrap_timeline_accounts: Accounts die altijd aan nieuwe gebruikers worden aanbevolen closed_registrations_message: Aangepast bericht wanneer registratie is uitgeschakeld - content_cache_retention_period: Bewaartermijn berichtencache + content_cache_retention_period: Bewaartermijn voor externe inhoud custom_css: Aangepaste CSS mascot: Aangepaste mascotte (legacy) media_cache_retention_period: Bewaartermijn mediacache diff --git a/config/locales/simple_form.nn.yml b/config/locales/simple_form.nn.yml index a9f5f609fa..51dce245d2 100644 --- a/config/locales/simple_form.nn.yml +++ b/config/locales/simple_form.nn.yml @@ -77,13 +77,13 @@ nn: warn: Skjul det filtrerte innhaldet bak ei åtvaring som nemner tittelen på filteret form_admin_settings: activity_api_enabled: Tal på lokale innlegg, aktive brukarar og nyregistreringar kvar veke - backups_retention_period: Ta vare på genererte brukararkiv i angitt antal dagar. + backups_retention_period: Brukarar har moglegheit til å generere arkiv av sine innlegg for å laste ned seinare. Når sett til ein positiv verdi, blir desse arkiva automatisk sletta frå lagringa etter eit gitt antal dagar. bootstrap_timeline_accounts: Desse kontoane vil bli festa øverst på fylgjaranbefalingane til nye brukarar. closed_registrations_message: Vist når det er stengt for registrering - content_cache_retention_period: Innlegg frå andre tenarar vil bli sletta etter det angitte talet på dagar når det er sett til ein positiv verdi. Dette kan vera irreversibelt. + content_cache_retention_period: Alle innlegg frå andre serverar (inkludert boostar og svar) vil bli sletta etter dei gitte antal dagar, uten hensyn til lokale brukarinteraksjonar med desse innlegga. Dette inkluderer innlegg der ein lokal brukar har merka det som bokmerker eller som favorittar. Òg private nemningar mellom brukarar frå ulike førekomstar vil gå tapt og vere umogleg å gjenskape. Bruk av denne innstillinga er rekna på spesielle førekomstar og bryt mange brukarforventingar når dette blir tatt i generell bruk. custom_css: Du kan bruka eigendefinerte stilar på nettversjonen av Mastodon. mascot: Overstyrer illustrasjonen i det avanserte webgrensesnittet. - media_cache_retention_period: Mediafiler som har blitt lasta ned vil bli sletta etter det angitte talet på dagar når det er sett til ein positiv verdi, og lasta ned på nytt ved etterspørsel. + media_cache_retention_period: Mediafiler frå innlegg laga av eksterne brukarar blir bufra på serveren din. Når sett til ein positiv verdi, slettast media etter eit gitt antal dagar. Viss mediedata blir førespurt etter det er sletta, vil dei bli lasta ned på nytt viss kjelda sitt innhald framleis er tilgjengeleg. På grunn av restriksjonar på kor ofte lenkeførehandsvisningskort lastar tredjepart-nettstadar, rådast det til å setje denne verdien til minst 14 dagar, eller at førehandsvisningskort ikkje blir oppdatert på førespurnad før det tidspunktet. peers_api_enabled: Ei liste over domenenamn denne tenaren har møtt på i allheimen. Det står ingenting om tenaren din samhandlar med ein annan tenar, berre om tenaren din veit om den andre. Dette blir brukt av tenester som samlar statistikk om føderering i det heile. profile_directory: Profilkatalogen viser alle brukarar som har valt å kunne bli oppdaga. require_invite_text: Når registrering krev manuell godkjenning, lyt du gjera tekstfeltet "Kvifor vil du bli med?" obligatorisk i staden for valfritt @@ -243,7 +243,7 @@ nn: backups_retention_period: Arkiveringsperiode for brukararkiv bootstrap_timeline_accounts: Tilrå alltid desse kontoane for nye brukarar closed_registrations_message: Eigendefinert melding når registrering ikkje er mogleg - content_cache_retention_period: Oppbevaringsperiode for innhaldsbuffer + content_cache_retention_period: Oppbevaringstid for eksternt innhald custom_css: Egendefinert CSS mascot: Eigendefinert maskot (eldre funksjon) media_cache_retention_period: Oppbevaringsperiode for mediebuffer diff --git a/config/locales/simple_form.no.yml b/config/locales/simple_form.no.yml index a1050c9f91..de3788aa42 100644 --- a/config/locales/simple_form.no.yml +++ b/config/locales/simple_form.no.yml @@ -77,13 +77,10 @@ warn: Skjul det filtrerte innholdet bak et varsel som omtaler filterets tittel form_admin_settings: activity_api_enabled: Teller med lokale publiserte innlegg, aktive brukere og nye registreringer i ukentlige bøtter - backups_retention_period: Behold genererte brukerarkiv i det angitte antall dager. bootstrap_timeline_accounts: Disse kontoene vil bli festet til toppen av nye brukeres følge-anbefalinger. closed_registrations_message: Vises når det er stengt for registrering - content_cache_retention_period: Innlegg fra andre tjenere vil slettes etter det angitte antall dager når det er satt til en positiv verdi. Dette kan være irreversibelt. custom_css: Du kan bruke egendefinerte stiler på nettversjonen av Mastodon. mascot: Overstyrer illustrasjonen i det avanserte webgrensesnittet. - media_cache_retention_period: Mediafiler som lastes ned vil bli slettet etter det angitte antall dager når det settes til en positiv verdi, og blir lastet ned på nytt ved behov. peers_api_enabled: En liste over domenenavn denne serveren har oppstått i fødiverset. Det finnes ikke data om du føderer med en gitt server, for akkurat det serveren din vet om. Dette brukes av tjenester som i all hovedsak innhenter føderasjonsstatistikk. profile_directory: Profilkatalogen viser alle brukere som har valgt å kunne bli oppdaget. require_invite_text: Når registreringer krever manuell godkjenning, må du gjøre «Hvorfor vil du bli med?»-tekstinput obligatorisk i stedet for valgfritt @@ -242,7 +239,6 @@ backups_retention_period: Brukers oppbevaringsperiode for arkiv bootstrap_timeline_accounts: Anbefaler alltid disse kontoene til nye brukere closed_registrations_message: Egendefinert melding når registrering ikke er tilgjengelig - content_cache_retention_period: Oppbevaringsperiode for innholdsbuffer custom_css: Egendefinert CSS mascot: Egendefinert maskot (legacy) media_cache_retention_period: Oppbevaringsperiode for mediebuffer diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml index 3a1c619f70..5c0c640287 100644 --- a/config/locales/simple_form.pl.yml +++ b/config/locales/simple_form.pl.yml @@ -77,13 +77,13 @@ pl: warn: Ukryj filtrowaną zawartość za ostrzeżeniem wskazującym tytuł filtra form_admin_settings: activity_api_enabled: Liczby opublikowanych lokalnych postów, aktywnych użytkowników i nowych rejestracji w tygodniowych przedziałach - backups_retention_period: Zachowaj wygenerowane archiwa użytkownika przez określoną liczbę dni. + backups_retention_period: Użytkownicy mogą generować archiwa wpisów do późniejszego pobrania. Jeżeli ta wartość jest dodatnia, te archiwa zostaną automatycznie usunięte z twojego serwera po danej liczbie dni. bootstrap_timeline_accounts: Te konta zostaną przypięte na górze rekomendacji obserwacji nowych użytkowników. closed_registrations_message: Wyświetlane po zamknięciu rejestracji - content_cache_retention_period: Posty z innych serwerów zostaną usunięte po określonej liczbie dni, kiedy liczba jest ustawiona na wartość dodatnią. Może to być nieodwracalne. + content_cache_retention_period: Wszystkie wpisy z innych serwerów (w tym podbicia i odpowiedzi) zostaną usunięte po danej liczbie dni, bez względu na interakcje z nimi twoich użytkowników. Zawierają się w tym wpisy, które twoi użytkownicy dodali do zakładek lub ulubionych. Prywatne wzmianki od innych instancji zostaną utracone i będą nieprzywracalne. To ustawienie jest przeznaczone dla instancji zastosowania specjalnego i jest niezgodne z wieloma oczekiwaniami użytkowników. custom_css: Możesz zastosować niestandardowe style w internetowej wersji Mastodon. mascot: Nadpisuje ilustrację w zaawansowanym interfejsie internetowym. - media_cache_retention_period: Pobrane pliki multimedialne zostaną usunięte po określonej liczbie dni po ustawieniu na wartość dodatnią i ponownie pobrane na żądanie. + media_cache_retention_period: Media z wpisów od obcych użytkowników są cache'owane na twoim serwerze. Kiedy dana wartość jest dodatnia, media te będą usunięte po tylu dniach. Jeżeli usunięte media zostaną potem zażądane, oryginał zostanie ponownie pobrany (o ile jest dalej dostępny). Z powodu ograniczeń dot. częstotliwości z jaką karty podglądu linków dopytują się o dane od stron trzecich, zalecana wartość to min. 14 dni, bo karty podglądu linków nie będą wcześniej odświeżane na żądane. peers_api_enabled: Lista nazw domen, z którymi ten serwer spotkał się w fediverse. Nie są tu zawarte żadne dane o tym, czy użytkownik dokonuje federacji z danym serwerem, a jedynie, że jego serwer o tym wie. Jest to wykorzystywane przez serwisy, które zbierają statystyki dotyczące federacji w ogólnym sensie. profile_directory: Katalog profili zawiera listę wszystkich użytkowników, którzy zgodzili się na bycie znalezionymi. require_invite_text: Kiedy rejestracje wymagają ręcznego zatwierdzenia, ustaw pole "Dlaczego chcesz dołączyć?" jako obowiązkowe, a nie opcjonalne @@ -243,7 +243,7 @@ pl: backups_retention_period: Okres przechowywania archiwum użytkownika bootstrap_timeline_accounts: Zawsze rekomenduj te konta nowym użytkownikom closed_registrations_message: Niestandardowa wiadomość, gdy rejestracje nie są dostępne - content_cache_retention_period: Okres przechowywania pamięci podręcznej + content_cache_retention_period: Okres zachowywania zdalnych treści custom_css: Niestandardowy CSS mascot: Własna ikona media_cache_retention_period: Okres przechowywania pamięci podręcznej diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml index c3eea9f118..f68eef8a63 100644 --- a/config/locales/simple_form.pt-BR.yml +++ b/config/locales/simple_form.pt-BR.yml @@ -77,13 +77,10 @@ pt-BR: warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro form_admin_settings: activity_api_enabled: Contagem de publicações locais, usuários ativos e novos usuários semanais - backups_retention_period: Manter os arquivos de usuário gerados pelo número de dias especificados. bootstrap_timeline_accounts: Estas contas serão fixadas no topo das recomendações de novos usuários para seguir. closed_registrations_message: Exibido quando as inscrições estiverem fechadas - content_cache_retention_period: Postagens de outros servidores serão excluídas após o número de dias especificados, quando definido com um valor positivo. Isso pode ser irreversível. custom_css: Você pode aplicar estilos personalizados na versão da web do Mastodon. mascot: Substitui a ilustração na interface web avançada. - media_cache_retention_period: Os arquivos de mídia baixados serão excluídos após o número especificado de dias, quando definido para um valor positivo, e baixados novamente na demanda. peers_api_enabled: Uma lista de nomes de domínio que este servidor encontrou no "fediverse". Nenhum dado é incluído aqui sobre se você concorda com os padroes operacionais de um determinado servidor, apenas que o seu servidor sabe disso. Esta ferramenta é utilizado por serviços que recolhem estatísticas sob as normas da federação (grupo de empresas que concordam sob paramentros operacionais específicos), em termos gerais. profile_directory: O diretório de perfis lista todos os usuários que optaram por permitir que suas contas sejam descobertas. require_invite_text: 'Quando o cadastro de novas contas exigir aprovação manual, tornar obrigatório, ao invés de opcional, o texto de solicitação de convite: "Por que você deseja ingressar nessa comunidade?"' @@ -243,7 +240,6 @@ pt-BR: backups_retention_period: Período de retenção do arquivo de usuário bootstrap_timeline_accounts: Sempre recomendar essas contas para novos usuários closed_registrations_message: Mensagem personalizada quando inscrições não estão disponíveis - content_cache_retention_period: Período de retenção do cachê de conteúdo custom_css: CSS personalizável mascot: Mascote personalizado (legado) media_cache_retention_period: Período de retenção do cachê de mídia diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml index a84f97f88d..3292c48289 100644 --- a/config/locales/simple_form.pt-PT.yml +++ b/config/locales/simple_form.pt-PT.yml @@ -77,13 +77,10 @@ pt-PT: warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro form_admin_settings: activity_api_enabled: Contagem, em blocos semanais, de publicações locais, utilizadores ativos e novos registos - backups_retention_period: Manter os ficheiros gerados pelos utilizadores durante um número concreto de dias. bootstrap_timeline_accounts: Estas contas serão destacadas no topo das recomendações aos novos utilizadores. closed_registrations_message: Apresentado quando as inscrições estiverem encerradas - content_cache_retention_period: Publicações de outros servidores serão apagadas decorrido o número de dias especificado, se estiver definido um valor positivo. Isso pode ser irreversível. custom_css: Pode aplicar estilos personalizados na versão web do Mastodon. mascot: Sobrepõe-se à ilustração na interface web avançada. - media_cache_retention_period: Os ficheiros de media descarregados serão apagados decorrido o número de dias especificado, quando definido com um valor positivo, e descarregados novamente quando solicitados. peers_api_enabled: Uma lista de nomes de domínio que este servidor encontrou no fediverso. Nenhum dado é incluído aqui sobre se você federa com um determinado servidor, apenas que o seu servidor o conhece. Este serviço é utilizado por serviços que recolhem estatísticas na federação, em termos gerais. profile_directory: O diretório de perfis lista todos os utilizadores que optaram por ter a sua conta a ser sugerida a outros. require_invite_text: Quando as incrições exigirem aprovação manual, faça o texto "Por que se quer juntar a nós?" da solicitação de convite ser obrigatório, em vez de opcional @@ -243,7 +240,6 @@ pt-PT: backups_retention_period: Período de retenção de arquivos de utilizador bootstrap_timeline_accounts: Recomendar sempre estas contas para novos utilizadores closed_registrations_message: Mensagem personalizada quando as inscrições não estiverem disponíveis - content_cache_retention_period: Período de retenção de conteúdo em cache custom_css: CSS personalizado mascot: Mascote personalizada (legado) media_cache_retention_period: Período de retenção de ficheiros de media em cache diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml index 192a2f96df..a050b5a529 100644 --- a/config/locales/simple_form.ru.yml +++ b/config/locales/simple_form.ru.yml @@ -75,13 +75,10 @@ ru: warn: Скрыть отфильтрованный контент за предупреждением с указанием названия фильтра form_admin_settings: activity_api_enabled: Подсчёт количества локальных постов, активных пользователей и новых регистраций на еженедельной основе - backups_retention_period: Сохранять сгенерированные пользовательские архивы для указанного количества дней. bootstrap_timeline_accounts: Эти аккаунты будут рекомендованы для подписки новым пользователям. closed_registrations_message: Отображается, когда регистрация закрыта - content_cache_retention_period: Записи с других серверов будут удалены после указанного количества дней, когда установлено положительное значение. Это может быть необратимо. custom_css: Вы можете применять пользовательские стили в веб-версии Mastodon. mascot: Заменяет иллюстрацию в расширенном веб-интерфейсе. - media_cache_retention_period: Скачанные медиа-файлы будут удалены после указанного количества дней, когда установлено положительное значение и повторно загружены по требованию. peers_api_enabled: Список доменных имен, с которыми сервер столкнулся в fediverse. Здесь нет данных о том, федерировались ли вы с данным сервером, только что ваш сервер знает об этом. Это используется службами, которые собирают статистику по федерации в общем смысле. profile_directory: В каталоге профилей перечислены все пользователи, которые согласились быть доступными для обнаружения. require_invite_text: Когда регистрация требует ручного одобрения, сделайте текстовый ввод "Почему вы хотите присоединиться?" обязательным, а не опциональным @@ -240,7 +237,6 @@ ru: backups_retention_period: Период хранения архива пользователя bootstrap_timeline_accounts: Всегда рекомендовать эти учетные записи новым пользователям closed_registrations_message: Сообщение, когда регистрация недоступна - content_cache_retention_period: Период хранения кэша содержимого custom_css: Пользовательский CSS mascot: Пользовательский маскот (устаревшее) media_cache_retention_period: Период хранения кэша медиафайлов diff --git a/config/locales/simple_form.sco.yml b/config/locales/simple_form.sco.yml index 7eeaca375a..f9dc4ba291 100644 --- a/config/locales/simple_form.sco.yml +++ b/config/locales/simple_form.sco.yml @@ -63,13 +63,10 @@ sco: hide: Totally plank the filtert content, ackin as if it didnae exist warn: Plank the filtert content ahin a warnin menshiein the filter's title form_admin_settings: - backups_retention_period: Haud generatit uiser archives fir the specified nummer o days. bootstrap_timeline_accounts: Thir accoonts wull get preenit tae the tap o new uisers' follae recommendations. closed_registrations_message: Displayit whan sign-ups is shut - content_cache_retention_period: Posts fae ither servers wull get deletit efter the specified nummer o days whan set tae a positive value. This wull mibbie be irreversible. custom_css: Ye kin pit custom styles on tae the web version o Mastodon. mascot: Owerrides the illustration in the advanced web interface. - media_cache_retention_period: Doonloadit media files wull be deletit efter the specified nummer o days whan set tae a positive value, an re-doonloadit on demand. profile_directory: The profile directory lists aw uisers thit hae opted-in fir tae be discoverable. require_invite_text: Whan sign-ups require approval bi haun, mak the “Hou dae ye want tae jyne?” text input mandatory raither nor optional site_contact_email: Hou fowk kin reach ye fir legal or support inquiries. @@ -216,7 +213,6 @@ sco: backups_retention_period: Uiser archive retention period bootstrap_timeline_accounts: Aye recommend thir accoonts tae new uisers closed_registrations_message: Custom message whan sign-ups urnae available - content_cache_retention_period: Content cache retention period custom_css: Custom CSS mascot: Custom mascot (legacy) media_cache_retention_period: Media cache retention period diff --git a/config/locales/simple_form.sl.yml b/config/locales/simple_form.sl.yml index cbf0570187..a4abb737c0 100644 --- a/config/locales/simple_form.sl.yml +++ b/config/locales/simple_form.sl.yml @@ -77,13 +77,10 @@ sl: warn: Skrij filtrirano vsebino za opozorilom, ki pomenja naslov filtra form_admin_settings: activity_api_enabled: Številke krajevno objavljenih objav, dejavnih uporabnikov in novih registracij na tedenskih seznamih - backups_retention_period: Hani tvorjene arhive uporabnikov navedeno število dni. bootstrap_timeline_accounts: Ti računi bodo pripeti na vrh priporočenih sledenj za nove uporabnike. closed_registrations_message: Prikazano, ko so registracije zaprte - content_cache_retention_period: Objave z drugih strežnikov bodo izbrisane po navedenem številu dni, če je vrednost pozitivna. Ta dejanja lahko nepovratna. custom_css: Spletni različici Mastodona lahko uveljavite sloge po meri. mascot: Preglasi ilustracijo v naprednem spletnem vmesniku. - media_cache_retention_period: Prenesene predstavnostne datoteke bodo izbrisane po navedenem številu dni, če je vrednost pozitivna, in ponovno prenesene na zahtevo. peers_api_enabled: Seznam imen domen, na katere je ta strežnik naletel v fediverzumu. Sem niso vključeni podatki o tem, ali ste v federaciji z danim strežnikom, zgolj to, ali vaš strežnik ve zanj. To uporabljajo storitve, ki zbirajo statistične podatke o federaciji v splošnem smislu. profile_directory: Imenik profilov izpiše vse uporabnike, ki so dovolili, da so v njem navedeni. require_invite_text: Če registracije zahtevajo ročno potrditev, nastavite vnos besedila pod »Zakaj se želite pridružiti?« za obveznega. @@ -243,7 +240,6 @@ sl: backups_retention_period: Obdobje hrambe arhivov uporabnikov bootstrap_timeline_accounts: Vedno priporočaj te račune novim uporabnikom closed_registrations_message: Sporočilo po meri, ko registracije niso na voljo - content_cache_retention_period: Obdobje hrambe predpomnilnika vsebine custom_css: CSS po meri mascot: Maskota po meri (opuščeno) media_cache_retention_period: Obdobje hrambe predpomnilnika predstavnosti diff --git a/config/locales/simple_form.sq.yml b/config/locales/simple_form.sq.yml index 41ee3d9bd5..a6c9303380 100644 --- a/config/locales/simple_form.sq.yml +++ b/config/locales/simple_form.sq.yml @@ -77,13 +77,10 @@ sq: warn: Fshihe lëndën e filtruar pas një sinjalizimi që përmend titullin e filtrit form_admin_settings: activity_api_enabled: Numër postimesh të botuar lokalisht, përdoruesish aktiv dhe regjistrimesh të reja sipas matjesh javore - backups_retention_period: Mbaji arkivat e prodhuara të përdoruesve për aq ditë sa numri i dhënë. bootstrap_timeline_accounts: Këto llogari do të fiksohen në krye të rekomandimeve për ndjekje nga përdorues të rinj. closed_registrations_message: Shfaqur kur mbyllen dritare regjistrimesh - content_cache_retention_period: Postimet prej shërbyesve të tjerë do të fshihen pas numrit të dhënë të ditëve, kur këtij i jepet një vlerë pozitive. Kjo mund të jetë e pakthyeshme. custom_css: Stile vetjakë mund të aplikoni në versionin web të Mastodon-it. mascot: Anashkalon ilustrimin te ndërfaqja web e thelluar. - media_cache_retention_period: Kartelat media të shkarkuara do të fshihen pas numrit të dhënë të ditëve, kur këtij i jepet një vlerë pozitive dhe rishkarkohen po u kërkua. peers_api_enabled: Një listë emrash përkatësish që ky shërbyes ka hasur në fedivers. Këtu s’jepen të dhëna nëse jeni i federuar me shërbyesin e dhënë, thjesht tregohet se shërbyesi juaj e njeh. Kjo përdoret nga shërbime që mbledhin statistika mbi federimin në kuptimin e përgjithshëm. profile_directory: Drejtoria e profileve paraqet krejt përdoruesit që kanë zgjedhur të jenë të zbulueshëm. require_invite_text: Kur regjistrimet lypin miratim dorazi, bëje tekstin “Përse doni të bëheni pjesë?” të detyrueshëm, në vend se opsional @@ -243,7 +240,6 @@ sq: backups_retention_period: Periudhë mbajtjeje arkivash përdoruesish bootstrap_timeline_accounts: Rekomandoju përherë këto llogari përdoruesve të rinj closed_registrations_message: Mesazh vetjak për pamundësi regjistrimesh të reja - content_cache_retention_period: Periudhë mbajtjeje lënde fshehtine custom_css: CSS Vetjake mascot: Simbol vetjak (e dikurshme) media_cache_retention_period: Periudhë mbajtjeje lënde media diff --git a/config/locales/simple_form.sr-Latn.yml b/config/locales/simple_form.sr-Latn.yml index 13296a04ce..bc4eafb965 100644 --- a/config/locales/simple_form.sr-Latn.yml +++ b/config/locales/simple_form.sr-Latn.yml @@ -77,13 +77,10 @@ sr-Latn: warn: Sakrij filtrirani sadržaj iza upozorenja u kome se navodi naziv filtera form_admin_settings: activity_api_enabled: Brojevi lokalno postavljenih objava, aktivnih korisnika i novih registracija na nedeljnoj bazi - backups_retention_period: Čuvaj generisane korisničke arhive navedeni broj dana. bootstrap_timeline_accounts: Ovi nalozi će biti zakačeni na vrh preporuka za praćenje novih korisnika. closed_registrations_message: Prikazuje se kada su registracije zatvorene - content_cache_retention_period: Sve objave i podržavanja sa drugih servera će biti izbrisani nakon navedenog broja dana. Neke objave se možda neće moći oporaviti. Svi povezani obeleživači, omiljeni i podržavanja će takođe biti izgubljeni i nemoguće je opozvati radnju. custom_css: Možete da primenite prilagođene stilove na veb verziji Mastodon-a. mascot: Zamenjuje ilustraciju u naprednom veb okruženju. - media_cache_retention_period: Kada se postavi na pozitivnu vrednost, preuzete medijske datoteke će biti izbrisane nakon navedenog broja dana, i ponovo preuzete na zahtev. peers_api_enabled: Lista domena sa kojima se ovaj server susreo u fediverzumu. Ovde nisu sadržani podaci o tome da li se Vaš server federiše sa drugim serverima, već samo da Vaš server zna za njih. Ove informacije koriste servisi koji prikupljaju podatke i vode statistiku o federaciji u širem smislu. profile_directory: Direktorijum profila navodi sve korisnike koji su se opredelili da budu vidljivi. require_invite_text: Kada registracije zahtevaju ručno odobrenje, postavite da odgovor na „Zašto želite da se pridružite?“ bude obavezan, a ne opcionalan @@ -243,7 +240,6 @@ sr-Latn: backups_retention_period: Period čuvanja korisničke arhive bootstrap_timeline_accounts: Uvek preporuči ove naloge novim korisnicima closed_registrations_message: Prilagođena poruka kada prijave nisu moguće - content_cache_retention_period: Period čuvanja keša sadržaja custom_css: Prilagođeni CSS mascot: Prilagođena maskota (nasleđe) media_cache_retention_period: Period čuvanja keša medija diff --git a/config/locales/simple_form.sr.yml b/config/locales/simple_form.sr.yml index 9820482182..006f4cf6d2 100644 --- a/config/locales/simple_form.sr.yml +++ b/config/locales/simple_form.sr.yml @@ -77,13 +77,10 @@ sr: warn: Сакриј филтрирани садржај иза упозорења у коме се наводи назив филтера form_admin_settings: activity_api_enabled: Бројеви локално постављених објава, активних корисника и нових регистрација на недељној бази - backups_retention_period: Чувај генерисане корисничке архиве наведени број дана. bootstrap_timeline_accounts: Ови налози ће бити закачени на врх препорука за праћење нових корисника. closed_registrations_message: Приказује се када су регистрације затворене - content_cache_retention_period: Све објаве и подржавања са других сервера ће бити избрисани након наведеног броја дана. Неке објаве се можда неће моћи опоравити. Сви повезани обележивачи, омиљени и подржавања ће такође бити изгубљени и немогуће је опозвати радњу. custom_css: Можете да примените прилагођене стилове на веб верзији Mastodon-а. mascot: Замењује илустрацију у напредном веб окружењу. - media_cache_retention_period: Када се постави на позитивну вредност, преузете медијске датотеке ће бити избрисане након наведеног броја дана, и поново преузете на захтев. peers_api_enabled: Листа домена са којима се овај сервер сусрео у федиверзуму. Овде нису садржани подаци о томе да ли се Ваш сервер федерише са другим серверима, већ само да Ваш сервер зна за њих. Ове информације користе сервиси који прикупљају податке и воде статистику о федерацији у ширем смислу. profile_directory: Директоријум профила наводи све кориснике који су се определили да буду видљиви. require_invite_text: Када регистрације захтевају ручно одобрење, поставите да одговор на „Зашто желите да се придружите?“ буде обавезан, а не опционалан @@ -243,7 +240,6 @@ sr: backups_retention_period: Период чувања корисничке архиве bootstrap_timeline_accounts: Увек препоручи ове налоге новим корисницима closed_registrations_message: Прилагођена порука када пријаве нису могуће - content_cache_retention_period: Период чувања кеша садржаја custom_css: Прилагођени CSS mascot: Прилагођена маскота (наслеђе) media_cache_retention_period: Период чувања кеша медија diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml index 37372cac27..3ab16bf69b 100644 --- a/config/locales/simple_form.sv.yml +++ b/config/locales/simple_form.sv.yml @@ -77,13 +77,10 @@ sv: warn: Dölj det filtrerade innehållet bakom en varning som visar filtrets rubrik form_admin_settings: activity_api_enabled: Antalet lokalt publicerade inlägg, aktiva användare och nya registrerade konton per vecka - backups_retention_period: Behåll genererade användararkiv i det angivna antalet dagar. bootstrap_timeline_accounts: Dessa konton kommer fästas högst upp i nya användares följrekommendationer. closed_registrations_message: Visas när nyregistreringar är avstängda - content_cache_retention_period: Inlägg från andra servrar kommer att raderas efter det angivna antalet dagar när detta är inställt på ett positivt värde. Åtgärden kan vara oåterkallelig. custom_css: Du kan använda anpassade stilar på webbversionen av Mastodon. mascot: Åsidosätter illustrationen i det avancerade webbgränssnittet. - media_cache_retention_period: Nedladdade mediefiler kommer raderas efter det angivna antalet dagar, om inställt till ett positivt värde, och laddas ned på nytt vid behov. peers_api_enabled: En lista över domänen den här servern har stött på i fediversum. Ingen data inkluderas om du har federerat med servern, bara att din server känner till den. Detta används av tjänster som samlar statistik om federering i allmänhet. profile_directory: Profilkatalogen visar alla användare som har samtyckt till att bli upptäckbara. require_invite_text: Gör fältet "Varför vill du gå med?" obligatoriskt när nyregistreringar kräver manuellt godkännande @@ -243,7 +240,6 @@ sv: backups_retention_period: Lagringsperiod för användararkivet bootstrap_timeline_accounts: Rekommendera alltid dessa konton till nya användare closed_registrations_message: Anpassat meddelande när nyregistreringar inte är tillgängliga - content_cache_retention_period: Tid för bibehållande av innehållscache custom_css: Anpassad CSS mascot: Anpassad maskot (tekniskt arv) media_cache_retention_period: Tid för bibehållande av mediecache diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml index b41cf0bea6..bfc2d2e6b6 100644 --- a/config/locales/simple_form.th.yml +++ b/config/locales/simple_form.th.yml @@ -77,13 +77,10 @@ th: warn: ซ่อนเนื้อหาที่กรองอยู่หลังคำเตือนที่กล่าวถึงชื่อเรื่องของตัวกรอง form_admin_settings: activity_api_enabled: จำนวนโพสต์ที่เผยแพร่ในเซิร์ฟเวอร์, ผู้ใช้ที่ใช้งานอยู่ และการลงทะเบียนใหม่ในบักเก็ตรายสัปดาห์ - backups_retention_period: เก็บการเก็บถาวรผู้ใช้ที่สร้างขึ้นตามจำนวนวันที่ระบุ bootstrap_timeline_accounts: จะปักหมุดบัญชีเหล่านี้ไว้ด้านบนสุดของคำแนะนำการติดตามของผู้ใช้ใหม่ closed_registrations_message: แสดงเมื่อมีการปิดการลงทะเบียน - content_cache_retention_period: จะลบโพสต์และการดันทั้งหมดจากเซิร์ฟเวอร์อื่น ๆ หลังจากจำนวนวันที่ระบุ โพสต์บางส่วนอาจไม่สามารถกู้คืนได้ ที่คั่นหน้า, รายการโปรด และการดันที่เกี่ยวข้องทั้งหมดจะสูญหายและไม่สามารถเลิกทำได้เช่นกัน custom_css: คุณสามารถนำไปใช้ลักษณะที่กำหนดเองใน Mastodon รุ่นเว็บ mascot: เขียนทับภาพประกอบในส่วนติดต่อเว็บขั้นสูง - media_cache_retention_period: จะลบไฟล์สื่อที่ดาวน์โหลดหลังจากจำนวนวันที่ระบุเมื่อตั้งเป็นค่าบวก และดาวน์โหลดใหม่ตามความต้องการ peers_api_enabled: รายการชื่อโดเมนที่เซิร์ฟเวอร์นี้พบในจักรวาลสหพันธ์ ไม่มีข้อมูลรวมอยู่ที่นี่เกี่ยวกับว่าคุณติดต่อกับเซิร์ฟเวอร์ที่กำหนดหรือไม่ เพียงแค่ว่าเซิร์ฟเวอร์ของคุณทราบเกี่ยวกับเซิร์ฟเวอร์ที่กำหนด มีการใช้สิ่งนี้โดยบริการที่เก็บรวบรวมสถิติในการติดต่อกับภายนอกในความหมายทั่วไป profile_directory: ไดเรกทอรีโปรไฟล์แสดงรายการผู้ใช้ทั้งหมดที่ได้เลือกรับให้สามารถค้นพบได้ require_invite_text: เมื่อการลงทะเบียนต้องการการอนุมัติด้วยตนเอง ทำให้การป้อนข้อความ “ทำไมคุณจึงต้องการเข้าร่วม?” บังคับแทนที่จะไม่จำเป็น @@ -243,7 +240,7 @@ th: backups_retention_period: ระยะเวลาการเก็บรักษาการเก็บถาวรผู้ใช้ bootstrap_timeline_accounts: แนะนำบัญชีเหล่านี้ให้กับผู้ใช้ใหม่เสมอ closed_registrations_message: ข้อความที่กำหนดเองเมื่อการลงทะเบียนไม่พร้อมใช้งาน - content_cache_retention_period: ระยะเวลาการเก็บรักษาแคชเนื้อหา + content_cache_retention_period: ระยะเวลาการเก็บรักษาเนื้อหาระยะไกล custom_css: CSS ที่กำหนดเอง mascot: มาสคอตที่กำหนดเอง (ดั้งเดิม) media_cache_retention_period: ระยะเวลาการเก็บรักษาแคชสื่อ diff --git a/config/locales/simple_form.tr.yml b/config/locales/simple_form.tr.yml index 758d1dc4de..4ec35f1024 100644 --- a/config/locales/simple_form.tr.yml +++ b/config/locales/simple_form.tr.yml @@ -77,13 +77,13 @@ tr: warn: Süzgeçlenmiş içeriği, süzgecinin başlığından söz eden bir uyarının arkasında gizle form_admin_settings: activity_api_enabled: Yerel olarak yayınlanan gönderi, etkin kullanıcı ve yeni kayıtların haftalık sayıları - backups_retention_period: Üretilen kullanıcı arşivlerini belirli gün sayısı kadar sakla. + backups_retention_period: Kullanıcılar, gönderilerinin arşivlerini daha sonra indirmek üzere oluşturabilirler. Pozitif bir değer verdilğinde bu arşivler verilmiş olan gün sonunda deponuzdan otomatik olarak silinecektir. bootstrap_timeline_accounts: Bu hesaplar, yeni kullanıcıların takip önerilerinin tepesinde sabitlenecektir. closed_registrations_message: Kayıt olma kapalıyken görüntülenir - content_cache_retention_period: Pozitif bir sayı girildiğinde, diğer sunuculardan gelen gönderiler belirli bir gün sonra silinecektir. Silme geri alınamayabilir. + content_cache_retention_period: Diğer sunuculardaki (öne çıkarma ve yanıtlar da dahil olmak üzere) tüm gönderiler belirlenen gün sonunda, yerel bir kullanıcının etkileşimine bakılmadan, silinecektir. Yerel bir kullanıcının yerimlerine veya favorilerine eklediği gönderiler de dahildir. Farklı sunuculardaki kullanıcılar arasındaki özel bahsetmeler de kaybolacak ve geri getirilmeleri mümkün olmayacaktır. Bu ayarın kullanımı özel amaçlı sunucular içindir ve genel amaçlı kullanımda etkinleştirildiğinde kullanıcı beklentilerini karşılamayabilir. custom_css: Mastodon'un web sürümüne özel biçimler uygulayabilirsiniz. mascot: Gelişmiş web arayüzündeki illüstrasyonu geçersiz kılar. - media_cache_retention_period: Pozitif bir sayı girildiğinde, diğer sunuculardan indirilen medya dosyaları belirli bir gün sonra silinecektir, isteğe bağlı olarak tekrar indirilebilir. + media_cache_retention_period: Uzak kullanıcıların gönderilerindeki ortam dosyaları sunucunuzda önbelleklenir. Pozitif bir değer verildiğinde, ortam dosyaları belirlenen gün sonunda silinecektir. Eğer ortam dosyaları silindikten sonra istenirse, kaynak içerik hala mevcutsa, tekrar indirilecektir. Bağlantı önizleme kartlarının üçüncü parti siteleri yoklamasına ilişkin kısıtlamalar nedeniyle, bu değeri en azından 14 gün olarak ayarlamanız önerilir, yoksa bağlantı önizleme kartları bu süreden önce isteğe bağlı olarak güncellenmeyecektir. peers_api_enabled: Bu sunucunun fediverse'te karşılaştığı alan adlarının bir listesi. İlgili sunucuyla birleştirme mi yapıyorsunuz yoksa sunucunuz sadece onu biliyor mu hakkında bir bilgi burada yok. Bu blgi genel olarak federasyın hakkında istatistik toplamak isteyen hizmetler tarafından kullanılıyor. profile_directory: Profil dizini keşfedilebilir olmayı kabul eden tüm kullanıcıları listeler. require_invite_text: Kayıt olmak elle doğrulama gerektiriyorsa, "Neden katılmak istiyorsunuz?" metin girdisini isteğe bağlı yerine zorunlu yapın @@ -243,7 +243,7 @@ tr: backups_retention_period: Kullanıcı arşivi saklama süresi bootstrap_timeline_accounts: Bu hesapları yeni kullanıcılara her zaman öner closed_registrations_message: Kayıt olma mevcut değilken gösterilen özel ileti - content_cache_retention_period: İçerik önbelleği saklama süresi + content_cache_retention_period: Uzak içerik saklama süresi custom_css: Özel CSS mascot: Özel maskot (eski) media_cache_retention_period: Medya önbelleği saklama süresi diff --git a/config/locales/simple_form.uk.yml b/config/locales/simple_form.uk.yml index db8e4b4d27..1d69f5c579 100644 --- a/config/locales/simple_form.uk.yml +++ b/config/locales/simple_form.uk.yml @@ -77,16 +77,10 @@ uk: warn: Сховати відфільтрований вміст за попередженням, у якому вказано заголовок фільтра form_admin_settings: activity_api_enabled: Кількість локальних опублікованих дописів, активних і нових користувачів у тижневих розрізах - backups_retention_period: Зберігати створені архіви користувача вказану кількість днів. bootstrap_timeline_accounts: Ці облікові записи будуть закріплені в топі пропозицій для нових користувачів. closed_registrations_message: Показується, коли реєстрація закрита - content_cache_retention_period: |- - Матеріали з інших серверів будуть видалені після вказаної кількості днів, коли встановлено позитивне значення. Ця дія може бути незворотна. - - Матеріали з інших серверів будуть видалені після вказаної кількості днів. Ця дія може бути незворотна. Усі пов'язані з ними закладки та поширення також будуть втрачені. custom_css: Ви можете застосувати користувацькі стилі у вебверсії Mastodon. mascot: Змінює ілюстрацію в розширеному вебінтерфейсі. - media_cache_retention_period: Завантажені медіафайли будуть видалені після вказаної кількості днів після встановлення додатного значення та повторного завантаження за запитом. peers_api_enabled: Список доменів імен цього сервера з'явився у федівсесвіті. Сюди не входять дані чи ви пов'язані федерацією з цим сервером, а лише відомості, що вашому серверу відомо про нього. Його використовують служби, які збирають загальну статистику про федерації. profile_directory: У каталозі профілів перераховані всі користувачі, які погодились бути видимими. require_invite_text: Якщо реєстрація вимагає власноручного затвердження, зробіть текстове поле «Чому ви хочете приєднатися?» обов'язковим, а не додатковим @@ -246,7 +240,7 @@ uk: backups_retention_period: Період утримання архіву користувача bootstrap_timeline_accounts: Завжди рекомендувати новим користувачам ці облікові записи closed_registrations_message: Показуване повідомлення, якщо реєстрація недоступна - content_cache_retention_period: Час зберігання кешу контенту + content_cache_retention_period: Період збереження віддаленого вмісту custom_css: Користувацький CSS mascot: Користувацький символ (застарілий) media_cache_retention_period: Період збереження кешу медіа diff --git a/config/locales/simple_form.vi.yml b/config/locales/simple_form.vi.yml index f4d9f526b6..bc9a181ed3 100644 --- a/config/locales/simple_form.vi.yml +++ b/config/locales/simple_form.vi.yml @@ -77,13 +77,13 @@ vi: warn: Ẩn nội dung đã lọc đằng sau một cảnh báo đề cập đến tiêu đề của bộ lọc form_admin_settings: activity_api_enabled: Số lượng tút được đăng trong máy chủ, người dùng đang hoạt động và đăng ký mới hàng tuần - backups_retention_period: Lưu trữ dữ liệu người dùng đã tạo trong số ngày được chỉ định. + backups_retention_period: Người dùng có khả năng tạo bản sao lưu các tút của họ để tải xuống sau. Các bản sao lưu này sẽ tự động bị xóa khỏi bộ nhớ của bạn sau số ngày được chỉ định. bootstrap_timeline_accounts: Những người này sẽ được ghim vào đầu các gợi ý theo dõi của người mới. closed_registrations_message: Được hiển thị khi đóng đăng ký - content_cache_retention_period: Tút từ các máy chủ khác sẽ bị xóa sau số ngày được chỉ định. Sau đó có thể không thể phục hồi được. + content_cache_retention_period: Tất cả tút từ các máy chủ khác (bao gồm cả đăng lại và trả lời) sẽ bị xóa sau số ngày được chỉ định mà không tính đến bất kỳ tương tác nào của người dùng cục bộ với các tút đó. Điều này bao gồm các tút mà người dùng cục bộ đã đánh dấu nó là dấu trang hoặc mục yêu thích. Những lượt nhắc riêng tư giữa những người dùng từ các máy chủ khác nhau cũng sẽ bị mất và không thể khôi phục. Việc sử dụng cài đặt này dành cho các trường hợp có mục đích đặc biệt và phá vỡ nhiều kỳ vọng của người dùng khi được triển khai cho mục đích sử dụng chung. custom_css: Bạn có thể tùy chỉnh phong cách trên bản web của Mastodon. mascot: Ghi đè hình minh họa trong giao diện web nâng cao. - media_cache_retention_period: Media đã tải xuống sẽ bị xóa sau số ngày được chỉ định và sẽ tải xuống lại theo yêu cầu. + media_cache_retention_period: Các tệp phương tiện từ các tút do người dùng máy chủ khác thực hiện sẽ được lưu vào bộ đệm trên máy chủ của bạn. Khi được đặt thành giá trị dương, phương tiện sẽ bị xóa sau số ngày được chỉ định. Nếu dữ liệu phương tiện được yêu cầu sau khi bị xóa, dữ liệu đó sẽ được tải xuống lại nếu nội dung nguồn vẫn còn. Do những hạn chế về tần suất thẻ xem trước liên kết thăm dò ý kiến ​​các trang web của bên thứ ba, bạn nên đặt giá trị này thành ít nhất 14 ngày, nếu không thẻ xem trước liên kết sẽ không được cập nhật theo yêu cầu trước thời gian đó. peers_api_enabled: Danh sách các máy chủ khác mà máy chủ này đã liên hợp. Không có dữ liệu nào được đưa vào đây về việc bạn có liên kết với một máy chủ nhất định hay không, chỉ là máy chủ của bạn biết về nó. Điều này được sử dụng bởi các dịch vụ thu thập số liệu thống kê về liên kết theo nghĩa chung. profile_directory: Liệt kê tất cả người đã chọn tham gia để có thể khám phá. require_invite_text: Khi đăng ký yêu cầu phê duyệt thủ công, hãy đặt câu hỏi "Tại sao bạn muốn tham gia?" nhập văn bản bắt buộc thay vì tùy chọn @@ -243,7 +243,7 @@ vi: backups_retention_period: Thời hạn lưu trữ nội dung người dùng sao lưu bootstrap_timeline_accounts: Luôn đề xuất những người này đến người mới closed_registrations_message: Thông báo tùy chỉnh khi tắt đăng ký - content_cache_retention_period: Thời hạn lưu trữ cache nội dung + content_cache_retention_period: Khoảng thời gian lưu giữ nội dung máy chủ khác custom_css: Tùy chỉnh CSS mascot: Tùy chỉnh linh vật (kế thừa) media_cache_retention_period: Thời hạn lưu trữ cache media diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml index 7f2eee023c..a06a5ab4e4 100644 --- a/config/locales/simple_form.zh-CN.yml +++ b/config/locales/simple_form.zh-CN.yml @@ -77,13 +77,13 @@ zh-CN: warn: 在警告中提及过滤器标题后,隐藏过滤内容 form_admin_settings: activity_api_enabled: 本站每周的嘟文数、活跃用户数和新注册用户数 - backups_retention_period: 将在指定天数内保留生成的用户存档。 + backups_retention_period: 用户可以生成其嘟文存档以供之后下载。当该值被设为正值时,这些存档将在指定的天数后自动从您的存储中删除。 bootstrap_timeline_accounts: 这些账号将在新用户关注推荐中置顶。 closed_registrations_message: 在关闭注册时显示 - content_cache_retention_period: 设为正数值时,来自其他服务器的嘟文将在指定天数后被删除。删除有可能会是不可逆的。 + content_cache_retention_period: 来自其它实例的所有嘟文(包括转嘟与回复)都将在指定天数后被删除,不论本实例用户是否与这些嘟文产生过交互。这包括被本实例用户喜欢和收藏的嘟文。实例间用户的私下提及也将丢失并无法恢复。此设置针对的是特殊用途的实例,用于一般用途时会打破许多用户的期望。 custom_css: 你可以为网页版 Mastodon 应用自定义样式。 mascot: 覆盖高级网页界面中的绘图形象。 - media_cache_retention_period: 设为正数值时,来自其他服务器的媒体文件将在指定天数后被删除,并在需要时再次下载。 + media_cache_retention_period: 来自外站用户嘟文的媒体文件将被缓存到你的实例上。当该值被设为正值时,缓存的媒体文件将在指定天数后被清除。如果媒体文件在被清除后重新被请求,且源站内容仍然可用,它将被重新下载。由于链接预览卡拉取第三方站点的频率受到限制,建议将此值设置为至少 14 天,如果小于该值,链接预览卡将不会按需更新。 peers_api_enabled: 此服务器在联邦宇宙中遇到的域名列表。 这里不包含关于您是否与给定服务器联合的数据,只是您的服务器知道它。 这由收集一般意义上的联邦统计信息的服务使用。 profile_directory: 个人资料目录会列出所有选择可被发现的用户。 require_invite_text: 当注册需要手动批准时,将“你为什么想要加入?”设为必填项 @@ -243,7 +243,7 @@ zh-CN: backups_retention_period: 用户存档保留期 bootstrap_timeline_accounts: 推荐新用户关注以下账号 closed_registrations_message: 在关闭注册时显示的自定义消息 - content_cache_retention_period: 内容缓存保留期 + content_cache_retention_period: 外站内容保留期 custom_css: 自定义 CSS mascot: 自定义吉祥物(旧) media_cache_retention_period: 媒体缓存保留期 diff --git a/config/locales/simple_form.zh-HK.yml b/config/locales/simple_form.zh-HK.yml index f6e40720fe..0e2ee81db7 100644 --- a/config/locales/simple_form.zh-HK.yml +++ b/config/locales/simple_form.zh-HK.yml @@ -77,13 +77,13 @@ zh-HK: warn: 將已篩選的內容隱藏在篩選器標題的警告後面。 form_admin_settings: activity_api_enabled: 每週本站發佈的帖文、活躍使用者及新註冊的數量 - backups_retention_period: 繼續封存生成的使用者到指定的天數。 + backups_retention_period: 使用者可以生成帖文存檔,以便日後下載。如果設定為正值,這些存檔將在指定天數後自動從你的儲存空間中刪除。 bootstrap_timeline_accounts: 這些帳號會被置頂在新使用者的追蹤建議上。 closed_registrations_message: 關閉註冊時顯示 - content_cache_retention_period: 當設定為正數時,來自其他伺服器的帖文將在指定天數後被刪除。無法還原這個操作。 + content_cache_retention_period: 所有來自其他伺服器的帖文(包括轉推和回覆),不論本站使用者有否與這些帖文互動,帖文都將在指定天數後被刪除。這包括本地使用者標記為書籤或加入最愛的帖文。不同站點之間的私人提及也將丟失,並且無法恢復。此設定適用於有特殊用途的站點,一般使用可能會破壞使用者體驗。 custom_css: 你可以在 Mastodon 網頁版套用自訂樣式。 mascot: 覆蓋進階網頁介面中的插圖。 - media_cache_retention_period: 當設定為正數時,已下載的媒體檔案將在指定天數後被刪除,並視乎需要重新下載。 + media_cache_retention_period: 遠端使用者帖文中的媒體檔案會緩存到你的伺服器上。當設定為正值時,媒體將在指定天數後被刪除。如果媒體資料在刪除後被請求,而源內容仍然可用,則會重新下載該媒體。由於連結預覽卡輪詢第三方網站的頻率有限制,建議將此值設定為至少 14 天,否則在此之前不會按需要更新連結預覽卡。 peers_api_enabled: 本伺服器於聯邦宇宙相遇的網域名單。這裏不包括你與某伺服器有否聯網的數據,僅表示你的伺服器已知的網域。這是供收集一般跨站數據的服務使用。 profile_directory: 個人檔案目錄羅列了所有選擇被發現的使用者。 require_invite_text: 如果需要手動審核註冊,請將「為何你想加入?」文字欄設定為必填,而非選填。 @@ -243,7 +243,7 @@ zh-HK: backups_retention_period: 封存使用者保留期 bootstrap_timeline_accounts: 總是向新使用者推薦這些帳號 closed_registrations_message: 無法註冊時的自訂訊息 - content_cache_retention_period: 內容快取保留期 + content_cache_retention_period: 遠端內容保留期 custom_css: 自訂 CSS mascot: 自訂吉祥物 (舊版) media_cache_retention_period: 媒體快取保留期 diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml index 69a2794e6c..a9e5921be0 100644 --- a/config/locales/simple_form.zh-TW.yml +++ b/config/locales/simple_form.zh-TW.yml @@ -77,13 +77,13 @@ zh-TW: warn: 隱藏過濾內容於過濾器標題之警告後 form_admin_settings: activity_api_enabled: 本站使用者的嘟文數量,以及本站的活躍使用者與一週內新使用者數量 - backups_retention_period: 將已產生的使用者封存資料保存特定天數。 + backups_retention_period: 使用者能產生他們嘟文的備份以便日後下載。當設定為正值時,這些嘟文備份將於指定之天數後自您的儲存空間中自動刪除。 bootstrap_timeline_accounts: 這些帳號將被釘選於新帳號跟隨推薦之上。 closed_registrations_message: 於註冊關閉時顯示 - content_cache_retention_period: 所有來自其他伺服器之嘟文及轉嘟將於指定天數後被刪除。這項操作可能是不可逆的。所有相關之書籤、最愛、轉嘟將會遺失並且無法回復。 + content_cache_retention_period: 所有來自其他伺服器之嘟文(包括轉嘟與回嘟)將於指定之天數後自動刪除,不論這些嘟文與本地使用者間的任何互動。這將包含本地使用者已標記為書籤或最愛之嘟文。不同站點使用者間之私訊亦將遺失且不可回復。此設定應適用於特殊情況,若常規使用將超乎多數使用者預期。 custom_css: 您於 Mastodon 網頁版本中能套用客製化風格。 mascot: 覆寫進階網頁介面中的圖例。 - media_cache_retention_period: 當設定成正值時,已下載的多媒體檔案會於指定天數後被刪除,並且視需要重新下載。 + media_cache_retention_period: 來自遠端伺服器嘟文中之多媒體內容將快取於您的伺服器。當設定為正值時,這些多媒體內容將於指定之天數後自您的儲存空間中自動刪除。若多媒體資料於刪除後被請求,且原始內容仍可存取,它們將被重新下載。由於連結預覽中第三方網站查詢頻率限制,建議將其設定為至少 14 日,否則於此之前連結預覽將不被即時更新。 peers_api_enabled: 浩瀚聯邦宇宙中與此伺服器曾經擦肩而過的網域列表。不包含關於您是否與此伺服器是否有與之串連,僅僅表示您的伺服器已知此網域。這是供收集聯邦宇宙中一般性統計資料服務使用。 profile_directory: 個人檔案目錄將會列出那些有選擇被發現的使用者。 require_invite_text: 如果已設定為手動審核註冊,請將「為什麼想要加入呢?」設定為必填項目。 @@ -243,7 +243,7 @@ zh-TW: backups_retention_period: 使用者封存資料保留期間 bootstrap_timeline_accounts: 永遠推薦這些帳號給新使用者 closed_registrations_message: 當註冊關閉時的客製化訊息 - content_cache_retention_period: 內容快取資料保留期間 + content_cache_retention_period: 遠端內容保留期限 custom_css: 自訂 CSS mascot: 自訂吉祥物 (legacy) media_cache_retention_period: 多媒體快取資料保留期間 diff --git a/config/locales/th.yml b/config/locales/th.yml index 17ff6a5ccb..0d7483d79a 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -737,6 +737,7 @@ th: desc_html: สิ่งนี้พึ่งพาสคริปต์ภายนอกจาก hCaptcha ซึ่งอาจเป็นข้อกังวลด้านความปลอดภัยและความเป็นส่วนตัว นอกจากนี้ สิ่งนี้สามารถทำให้กระบวนการการลงทะเบียนเข้าถึงได้น้อยลงอย่างมีนัยสำคัญสำหรับผู้คนบางส่วน (โดยเฉพาะอย่างยิ่งผู้พิการ) ด้วยเหตุผลเหล่านี้ โปรดพิจารณามาตรการทางเลือก เช่น การลงทะเบียนตามการอนุมัติหรือตามคำเชิญ title: ต้องให้ผู้ใช้ใหม่แก้ CAPTCHA เพื่อยืนยันบัญชีของเขา content_retention: + danger_zone: โซนอันตราย preamble: ควบคุมวิธีการจัดเก็บเนื้อหาที่ผู้ใช้สร้างขึ้นใน Mastodon title: การเก็บรักษาเนื้อหา default_noindex: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 4bd0e3455a..7b9cf50aaf 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -751,6 +751,7 @@ tr: desc_html: Bu, güvenlik ve gizlilikle ilgili bir endişe kaynağı olabilecek hCaptcha'nın harici komut dosyalarına dayanır. Ayrıca bu, kayıt sürecini bazı (özellikle engelli) kişiler için önemli ölçüde daha az erişilebilir hale getirebilir. Bu nedenlerle, lütfen onaya dayalı veya davete dayalı kayıt gibi alternatif önlemleri göz önünde bulundurun. title: Yeni kullanıcıların hesaplarını doğrulamaları için bir CAPTCHA çözmelerini gerektir content_retention: + danger_zone: Tehlikeli bölge preamble: Kullanıcıların ürettiği içeriğin Mastodon'da nasıl saklanacağını denetleyin. title: İçerik saklama default_noindex: diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 7c7652d699..5d0ebe2de0 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -779,6 +779,7 @@ uk: desc_html: Це залежить від зовнішніх скриптів hCaptcha, що може становити загрозу безпеці та приватності. Крім того, це може зробити процес реєстрації значно менш доступним для деяких людей (особливо з обмеженими можливостями). З цих причин, будь ласка, розгляньте альтернативні заходи, такі як реєстрація на основі схвалення або на основі запрошення. title: Вимагати нових користувачів розв'язувати CAPTCHA для підтвердження облікового запису content_retention: + danger_zone: Зони небезпеки preamble: Контролюйте, як зберігаються користувацькі матеріали в Mastodon. title: Зберігання вмісту default_noindex: diff --git a/config/locales/vi.yml b/config/locales/vi.yml index ec851a8284..5d9e881ea4 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -737,6 +737,7 @@ vi: desc_html: Điều này phụ thuộc vào các mã lệnh bên ngoài từ hCaptcha, đây có thể là mối lo ngại về bảo mật và quyền riêng tư. Thêm vào đó, điều này có thể làm cho quá trình đăng ký khó hơn đối với một số người (đặc biệt là người khuyết tật). Vì những lý do này, vui lòng xem xét các biện pháp thay thế như duyệt đăng ký thủ công hoặc tạo thư mời. title: Yêu cầu người dùng mới dùng CAPTCHA để xác minh tài khoản của họ content_retention: + danger_zone: Khu vực nguy hiểm preamble: Kiểm soát cách lưu trữ nội dung cá nhân trong Mastodon. title: Lưu giữ nội dung default_noindex: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 79764539dc..3140ebdd30 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -737,6 +737,7 @@ zh-CN: desc_html: 这依赖于来自hCaptcha的外部脚本,可能会带来安全和隐私问题。此外,这可能使注册过程对某些人(尤其是残疾人)的注册简易程度大幅下降。出于这些原因,请考虑采取其他措施,如基于批准或邀请的注册方式。 title: 要求新用户输入验证码以确认他们的账户 content_retention: + danger_zone: 危险操作区 preamble: 控制用户生成的内容在 Mastodon 中如何存储。 title: 内容保留 default_noindex: diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index 1dc50c2849..1bfbe38bb5 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -737,6 +737,7 @@ zh-HK: desc_html: 這倚賴 hCaptcha 的外部腳本,或會引起安全和私隱疑慮。此外,此註冊流程亦可能對特定人士(尤其是殘疾人士)有較多障礙。有鑑於此,請考慮使用其他以審核或邀請的註冊方式。 title: 要求新使用者解答 CAPTCHA 以驗證帳號 content_retention: + danger_zone: 危險區域 preamble: 控制使用者生成的內容如何儲存在 Mastodon。 title: 內容留存 default_noindex: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 407931c20c..cdedd759ea 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -739,6 +739,7 @@ zh-TW: 此外,這將大幅降低註冊流程對某些族群之易用性,特別是無障礙需求人士。基於此因,請考慮其他替代性方案,例如審核制或是邀請制之註冊流程。 title: 要求新使用者完成 CAPTCHA 挑戰以確認帳號 content_retention: + danger_zone: 危險區域! preamble: 控制使用者產生內容如何儲存於 Mastodon 上。 title: 內容保留期間 default_noindex: From 4527e012daa61dc07258eaedf3e03179b59fca8d Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 29 Apr 2024 10:23:05 +0200 Subject: [PATCH 033/658] Convert `entrypoints/sign_up` to Typescript (#30106) --- app/javascript/entrypoints/sign_up.js | 42 ----------------------- app/javascript/entrypoints/sign_up.ts | 48 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 42 deletions(-) delete mode 100644 app/javascript/entrypoints/sign_up.js create mode 100644 app/javascript/entrypoints/sign_up.ts diff --git a/app/javascript/entrypoints/sign_up.js b/app/javascript/entrypoints/sign_up.js deleted file mode 100644 index cf9c837773..0000000000 --- a/app/javascript/entrypoints/sign_up.js +++ /dev/null @@ -1,42 +0,0 @@ -import './public-path'; -import axios from 'axios'; - -import ready from '../mastodon/ready'; - -ready(() => { - setInterval(() => { - axios.get('/api/v1/emails/check_confirmation').then((response) => { - if (response.data) { - window.location = '/start'; - } - }).catch(error => { - console.error(error); - }); - }, 5000); - - document.querySelectorAll('.timer-button').forEach(button => { - let counter = 30; - - const container = document.createElement('span'); - - const updateCounter = () => { - container.innerText = ` (${counter})`; - }; - - updateCounter(); - - const countdown = setInterval(() => { - counter--; - - if (counter === 0) { - button.disabled = false; - button.removeChild(container); - clearInterval(countdown); - } else { - updateCounter(); - } - }, 1000); - - button.appendChild(container); - }); -}); diff --git a/app/javascript/entrypoints/sign_up.ts b/app/javascript/entrypoints/sign_up.ts new file mode 100644 index 0000000000..880738fcb7 --- /dev/null +++ b/app/javascript/entrypoints/sign_up.ts @@ -0,0 +1,48 @@ +import './public-path'; +import axios from 'axios'; + +import ready from '../mastodon/ready'; + +async function checkConfirmation() { + const response = await axios.get('/api/v1/emails/check_confirmation'); + + if (response.data) { + window.location.href = '/start'; + } +} + +ready(() => { + setInterval(() => { + void checkConfirmation(); + }, 5000); + + document + .querySelectorAll('button.timer-button') + .forEach((button) => { + let counter = 30; + + const container = document.createElement('span'); + + const updateCounter = () => { + container.innerText = ` (${counter})`; + }; + + updateCounter(); + + const countdown = setInterval(() => { + counter--; + + if (counter === 0) { + button.disabled = false; + button.removeChild(container); + clearInterval(countdown); + } else { + updateCounter(); + } + }, 1000); + + button.appendChild(container); + }); +}).catch((e: unknown) => { + throw e; +}); From f0c9cbaf3b079700b8179222d409c644dfd8ff66 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 05:01:46 -0400 Subject: [PATCH 034/658] Use `EXPIRATION_DURATIONS` constant in `CustomFilter` class (#30088) --- app/models/custom_filter.rb | 4 +++- app/views/filters/_filter_fields.html.haml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/models/custom_filter.rb b/app/models/custom_filter.rb index 2d8f5b6cba..94fadc7002 100644 --- a/app/models/custom_filter.rb +++ b/app/models/custom_filter.rb @@ -28,6 +28,8 @@ class CustomFilter < ApplicationRecord account ).freeze + EXPIRATION_DURATIONS = [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].freeze + include Expireable include Redisable @@ -52,7 +54,7 @@ class CustomFilter < ApplicationRecord return @expires_in if defined?(@expires_in) return nil if expires_at.nil? - [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].find { |expires_in| expires_in.from_now >= expires_at } + EXPIRATION_DURATIONS.find { |expires_in| expires_in.from_now >= expires_at } end def irreversible=(value) diff --git a/app/views/filters/_filter_fields.html.haml b/app/views/filters/_filter_fields.html.haml index 5b297a6a9e..0f4049ffb6 100644 --- a/app/views/filters/_filter_fields.html.haml +++ b/app/views/filters/_filter_fields.html.haml @@ -6,7 +6,7 @@ wrapper: :with_label .fields-row__column.fields-row__column-6.fields-group = f.input :expires_in, - collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), + collection: CustomFilter::EXPIRATION_DURATIONS.map(&:to_i), include_blank: I18n.t('invites.expires_in_prompt'), label_method: ->(i) { I18n.t("invites.expires_in.#{i}") }, wrapper: :with_label From 2123281f7c24620f81dde503b83674cb3824a8cd Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 05:02:47 -0400 Subject: [PATCH 035/658] Move `Account` limits to constants (#30087) --- app/models/account.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index 2bf00b2be5..3efa7d88bd 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -71,6 +71,9 @@ class Account < ApplicationRecord MENTION_RE = %r{(? { local? && will_save_change_to_username? && actor_type != 'Application' } + validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: USERNAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' } validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' } - validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? } - validates :note, note_length: { maximum: 500 }, if: -> { local? && will_save_change_to_note? } + validates :display_name, length: { maximum: DISPLAY_NAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_display_name? } + validates :note, note_length: { maximum: NOTE_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_note? } validates :fields, length: { maximum: DEFAULT_FIELDS_SIZE }, if: -> { local? && will_save_change_to_fields? } validates :uri, absence: true, if: :local?, on: :create validates :inbox_url, absence: true, if: :local?, on: :create From 6931cf5727907f9bc28568e028f28c4adc4caf6e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 09:03:27 +0000 Subject: [PATCH 036/658] Update dependency aws-sdk-s3 to v1.148.0 (#30076) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4f4ca89dc2..d73de0320f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -102,17 +102,17 @@ GEM attr_required (1.0.2) awrence (1.2.1) aws-eventstream (1.3.0) - aws-partitions (1.916.0) - aws-sdk-core (3.192.1) + aws-partitions (1.920.0) + aws-sdk-core (3.193.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.79.0) - aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-kms (1.80.0) + aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.147.0) - aws-sdk-core (~> 3, >= 3.192.0) + aws-sdk-s3 (1.148.0) + aws-sdk-core (~> 3, >= 3.193.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) From bbf1b603e0bb3c0ffeb4eba8a1d5faf645335d91 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 05:04:35 -0400 Subject: [PATCH 037/658] Remove unused `Account.popular` scope (#30068) --- app/models/account.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/account.rb b/app/models/account.rb index 3efa7d88bd..3c533822fd 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -138,7 +138,6 @@ class Account < ApplicationRecord scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) } scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.by_recent_status).references(:account_stat) } scope :by_recent_activity, -> { left_joins(:user, :account_stat).order(coalesced_activity_timestamps.desc).order(id: :desc) } - scope :popular, -> { order('account_stats.followers_count desc') } scope :by_domain_and_subdomains, ->(domain) { where(domain: Instance.by_domain_and_subdomains(domain).select(:domain)) } scope :not_excluded_by_account, ->(account) { where.not(id: account.excluded_from_timeline_account_ids) } scope :not_domain_blocked_by_account, ->(account) { where(arel_table[:domain].eq(nil).or(arel_table[:domain].not_in(account.excluded_from_timeline_domains))) } From 2739d8d5a493db7e6845ce85dc8534c275ab2cdc Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 05:10:23 -0400 Subject: [PATCH 038/658] Use shorter `render` call in `admin/webhooks` view (#30071) --- app/views/admin/webhooks/edit.html.haml | 2 +- app/views/admin/webhooks/new.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/webhooks/edit.html.haml b/app/views/admin/webhooks/edit.html.haml index 2c2a7aa034..abc9bdfabc 100644 --- a/app/views/admin/webhooks/edit.html.haml +++ b/app/views/admin/webhooks/edit.html.haml @@ -2,6 +2,6 @@ = t('admin.webhooks.edit') = simple_form_for @webhook, url: admin_webhook_path(@webhook) do |form| - = render partial: 'form', object: form + = render form .actions = form.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/webhooks/new.html.haml b/app/views/admin/webhooks/new.html.haml index f51b039ce8..50fcdc2be7 100644 --- a/app/views/admin/webhooks/new.html.haml +++ b/app/views/admin/webhooks/new.html.haml @@ -2,6 +2,6 @@ = t('admin.webhooks.new') = simple_form_for @webhook, url: admin_webhooks_path do |form| - = render partial: 'form', object: form + = render form .actions = form.button :button, t('admin.webhooks.add_new'), type: :submit From b9b4db483cc588a2eb334b63fe6740c8dad9b57b Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 29 Apr 2024 11:29:59 +0200 Subject: [PATCH 039/658] Remove usage of deprecated `defaultTypes` on React functional components (#30099) --- app/javascript/mastodon/components/badge.jsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/javascript/mastodon/components/badge.jsx b/app/javascript/mastodon/components/badge.jsx index 5e0b2587bd..2a335d7f50 100644 --- a/app/javascript/mastodon/components/badge.jsx +++ b/app/javascript/mastodon/components/badge.jsx @@ -7,7 +7,7 @@ import PersonIcon from '@/material-icons/400-24px/person.svg?react'; import SmartToyIcon from '@/material-icons/400-24px/smart_toy.svg?react'; -export const Badge = ({ icon, label, domain, roleId }) => ( +export const Badge = ({ icon = , label, domain, roleId }) => (
{icon} {label} @@ -22,10 +22,6 @@ Badge.propTypes = { roleId: PropTypes.string }; -Badge.defaultProps = { - icon: , -}; - export const GroupBadge = () => ( } label={} /> ); From a9816f051d3a83763b5a07423da2684fa2d05ca9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 05:33:06 -0400 Subject: [PATCH 040/658] Use shared form partial for `admin/warning_presets` views (#30069) --- app/views/admin/warning_presets/_form.html.haml | 7 +++++++ app/views/admin/warning_presets/edit.html.haml | 10 +++------- app/views/admin/warning_presets/index.html.haml | 10 +++------- 3 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 app/views/admin/warning_presets/_form.html.haml diff --git a/app/views/admin/warning_presets/_form.html.haml b/app/views/admin/warning_presets/_form.html.haml new file mode 100644 index 0000000000..cba74163c5 --- /dev/null +++ b/app/views/admin/warning_presets/_form.html.haml @@ -0,0 +1,7 @@ +.fields-group + = form.input :title, + wrapper: :with_block_label + +.fields-group + = form.input :text, + wrapper: :with_block_label diff --git a/app/views/admin/warning_presets/edit.html.haml b/app/views/admin/warning_presets/edit.html.haml index b5c5107ef4..f0bd9c12ec 100644 --- a/app/views/admin/warning_presets/edit.html.haml +++ b/app/views/admin/warning_presets/edit.html.haml @@ -1,14 +1,10 @@ - content_for :page_title do = t('admin.warning_presets.edit_preset') -= simple_form_for @warning_preset, url: admin_warning_preset_path(@warning_preset) do |f| += simple_form_for @warning_preset, url: admin_warning_preset_path(@warning_preset) do |form| = render 'shared/error_messages', object: @warning_preset - .fields-group - = f.input :title, wrapper: :with_block_label - - .fields-group - = f.input :text, wrapper: :with_block_label + = render form .actions - = f.button :button, t('generic.save_changes'), type: :submit + = form.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/warning_presets/index.html.haml b/app/views/admin/warning_presets/index.html.haml index b26a13d966..22fee21050 100644 --- a/app/views/admin/warning_presets/index.html.haml +++ b/app/views/admin/warning_presets/index.html.haml @@ -2,17 +2,13 @@ = t('admin.warning_presets.title') - if can? :create, :account_warning_preset - = simple_form_for @warning_preset, url: admin_warning_presets_path do |f| + = simple_form_for @warning_preset, url: admin_warning_presets_path do |form| = render 'shared/error_messages', object: @warning_preset - .fields-group - = f.input :title, wrapper: :with_block_label - - .fields-group - = f.input :text, wrapper: :with_block_label + = render form .actions - = f.button :button, t('admin.warning_presets.add_new'), type: :submit + = form.button :button, t('admin.warning_presets.add_new'), type: :submit %hr.spacer/ From e3364668946e4426b15df664a69624a9ea647263 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 05:33:27 -0400 Subject: [PATCH 041/658] Use shared form partial for `admin/rules` views (#30067) --- app/views/admin/rules/_form.html.haml | 7 +++++++ app/views/admin/rules/edit.html.haml | 10 +++------- app/views/admin/rules/index.html.haml | 10 +++------- 3 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 app/views/admin/rules/_form.html.haml diff --git a/app/views/admin/rules/_form.html.haml b/app/views/admin/rules/_form.html.haml new file mode 100644 index 0000000000..9fc54e2887 --- /dev/null +++ b/app/views/admin/rules/_form.html.haml @@ -0,0 +1,7 @@ +.fields-group + = form.input :text, + wrapper: :with_block_label + +.fields-group + = form.input :hint, + wrapper: :with_block_label diff --git a/app/views/admin/rules/edit.html.haml b/app/views/admin/rules/edit.html.haml index 77815588d2..9e3c915812 100644 --- a/app/views/admin/rules/edit.html.haml +++ b/app/views/admin/rules/edit.html.haml @@ -1,14 +1,10 @@ - content_for :page_title do = t('admin.rules.edit') -= simple_form_for @rule, url: admin_rule_path(@rule) do |f| += simple_form_for @rule, url: admin_rule_path(@rule) do |form| = render 'shared/error_messages', object: @rule - .fields-group - = f.input :text, wrapper: :with_block_label - - .fields-group - = f.input :hint, wrapper: :with_block_label + = render form .actions - = f.button :button, t('generic.save_changes'), type: :submit + = form.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/admin/rules/index.html.haml b/app/views/admin/rules/index.html.haml index dd15ce03c0..5a2789edcf 100644 --- a/app/views/admin/rules/index.html.haml +++ b/app/views/admin/rules/index.html.haml @@ -6,17 +6,13 @@ %hr.spacer/ - if can? :create, :rule - = simple_form_for @rule, url: admin_rules_path do |f| + = simple_form_for @rule, url: admin_rules_path do |form| = render 'shared/error_messages', object: @rule - .fields-group - = f.input :text, wrapper: :with_block_label - - .fields-group - = f.input :hint, wrapper: :with_block_label + = render form .actions - = f.button :button, t('admin.rules.add_new'), type: :submit + = form.button :button, t('admin.rules.add_new'), type: :submit %hr.spacer/ From 95e9de577752a71ed8804ecc5fcd314bca47adee Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 29 Apr 2024 11:45:58 +0200 Subject: [PATCH 042/658] Prevent accidental serialization of `Account` and `User` records (#30079) --- app/models/application_record.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 014a73997d..299aad6340 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -22,4 +22,10 @@ class ApplicationRecord < ActiveRecord::Base value end end + + # Prevent implicit serialization in ActiveModel::Serializer or other code paths. + # This is a hardening step to avoid accidental leaking of attributes. + def as_json + raise NotImplementedError + end end From ac7f4d57bb8f92ce0fbc91736cba8665174f41d4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 05:55:37 -0400 Subject: [PATCH 043/658] Use composable query in `Status.without_replies` scope (#30086) --- app/models/status.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/status.rb b/app/models/status.rb index c2d7985b4d..2ff803bf0b 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -106,7 +106,9 @@ class Status < ApplicationRecord scope :remote, -> { where(local: false).where.not(uri: nil) } scope :local, -> { where(local: true).or(where(uri: nil)) } scope :with_accounts, ->(ids) { where(id: ids).includes(:account) } - scope :without_replies, -> { where('statuses.reply = FALSE OR statuses.in_reply_to_account_id = statuses.account_id') } + scope :without_replies, -> { not_reply.or(reply_to_account) } + scope :not_reply, -> { where(reply: false) } + scope :reply_to_account, -> { where(arel_table[:in_reply_to_account_id].eq arel_table[:account_id]) } scope :without_reblogs, -> { where(statuses: { reblog_of_id: nil }) } scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) } scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) } From 7d3fe2b4c3cd9511df8f8026890c71b2119719f3 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 29 Apr 2024 11:55:41 +0200 Subject: [PATCH 044/658] Add loading indicator and empty result message to advanced interface search (#30085) --- .../compose/components/search_results.jsx | 112 +++++++++--------- .../containers/search_results_container.js | 20 ---- .../mastodon/features/compose/index.jsx | 4 +- app/javascript/mastodon/reducers/search.js | 1 + 4 files changed, 62 insertions(+), 75 deletions(-) delete mode 100644 app/javascript/mastodon/features/compose/containers/search_results_container.js diff --git a/app/javascript/mastodon/features/compose/components/search_results.jsx b/app/javascript/mastodon/features/compose/components/search_results.jsx index 667662781e..6a482c8ec2 100644 --- a/app/javascript/mastodon/features/compose/components/search_results.jsx +++ b/app/javascript/mastodon/features/compose/components/search_results.jsx @@ -1,16 +1,16 @@ -import PropTypes from 'prop-types'; +import { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; - import FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react'; import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; import TagIcon from '@/material-icons/400-24px/tag.svg?react'; +import { expandSearch } from 'mastodon/actions/search'; import { Icon } from 'mastodon/components/icon'; import { LoadMore } from 'mastodon/components/load_more'; +import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { SearchSection } from 'mastodon/features/explore/components/search_section'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; import { ImmutableHashtag as Hashtag } from '../../../components/hashtag'; import AccountContainer from '../../../containers/account_container'; @@ -26,62 +26,68 @@ const withoutLastResult = list => { } }; -class SearchResults extends ImmutablePureComponent { +export const SearchResults = () => { + const results = useAppSelector((state) => state.getIn(['search', 'results'])); + const isLoading = useAppSelector((state) => state.getIn(['search', 'isLoading'])); - static propTypes = { - results: ImmutablePropTypes.map.isRequired, - expandSearch: PropTypes.func.isRequired, - searchTerm: PropTypes.string, - }; + const dispatch = useAppDispatch(); - handleLoadMoreAccounts = () => this.props.expandSearch('accounts'); + const handleLoadMoreAccounts = useCallback(() => { + dispatch(expandSearch('accounts')); + }, [dispatch]); - handleLoadMoreStatuses = () => this.props.expandSearch('statuses'); + const handleLoadMoreStatuses = useCallback(() => { + dispatch(expandSearch('statuses')); + }, [dispatch]); - handleLoadMoreHashtags = () => this.props.expandSearch('hashtags'); + const handleLoadMoreHashtags = useCallback(() => { + dispatch(expandSearch('hashtags')); + }, [dispatch]); - render () { - const { results } = this.props; + let accounts, statuses, hashtags; - let accounts, statuses, hashtags; - - if (results.get('accounts') && results.get('accounts').size > 0) { - accounts = ( - }> - {withoutLastResult(results.get('accounts')).map(accountId => )} - {(results.get('accounts').size > INITIAL_PAGE_LIMIT && results.get('accounts').size % INITIAL_PAGE_LIMIT === 1) && } - - ); - } - - if (results.get('hashtags') && results.get('hashtags').size > 0) { - hashtags = ( - }> - {withoutLastResult(results.get('hashtags')).map(hashtag => )} - {(results.get('hashtags').size > INITIAL_PAGE_LIMIT && results.get('hashtags').size % INITIAL_PAGE_LIMIT === 1) && } - - ); - } - - if (results.get('statuses') && results.get('statuses').size > 0) { - statuses = ( - }> - {withoutLastResult(results.get('statuses')).map(statusId => )} - {(results.get('statuses').size > INITIAL_PAGE_LIMIT && results.get('statuses').size % INITIAL_PAGE_LIMIT === 1) && } - - ); - } - - - return ( -
- {accounts} - {hashtags} - {statuses} -
+ if (results.get('accounts') && results.get('accounts').size > 0) { + accounts = ( + }> + {withoutLastResult(results.get('accounts')).map(accountId => )} + {(results.get('accounts').size > INITIAL_PAGE_LIMIT && results.get('accounts').size % INITIAL_PAGE_LIMIT === 1) && } + ); } -} + if (results.get('hashtags') && results.get('hashtags').size > 0) { + hashtags = ( + }> + {withoutLastResult(results.get('hashtags')).map(hashtag => )} + {(results.get('hashtags').size > INITIAL_PAGE_LIMIT && results.get('hashtags').size % INITIAL_PAGE_LIMIT === 1) && } + + ); + } -export default SearchResults; + if (results.get('statuses') && results.get('statuses').size > 0) { + statuses = ( + }> + {withoutLastResult(results.get('statuses')).map(statusId => )} + {(results.get('statuses').size > INITIAL_PAGE_LIMIT && results.get('statuses').size % INITIAL_PAGE_LIMIT === 1) && } + + ); + } + + return ( +
+ {!accounts && !hashtags && !statuses && ( + isLoading ? ( + + ) : ( +
+ +
+ ) + )} + {accounts} + {hashtags} + {statuses} +
+ ); + +}; diff --git a/app/javascript/mastodon/features/compose/containers/search_results_container.js b/app/javascript/mastodon/features/compose/containers/search_results_container.js deleted file mode 100644 index 54c2af3177..0000000000 --- a/app/javascript/mastodon/features/compose/containers/search_results_container.js +++ /dev/null @@ -1,20 +0,0 @@ -import { connect } from 'react-redux'; - -import { expandSearch } from 'mastodon/actions/search'; -import { fetchSuggestions, dismissSuggestion } from 'mastodon/actions/suggestions'; - -import SearchResults from '../components/search_results'; - -const mapStateToProps = state => ({ - results: state.getIn(['search', 'results']), - suggestions: state.getIn(['suggestions', 'items']), - searchTerm: state.getIn(['search', 'searchTerm']), -}); - -const mapDispatchToProps = dispatch => ({ - fetchSuggestions: () => dispatch(fetchSuggestions()), - expandSearch: type => dispatch(expandSearch(type)), - dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))), -}); - -export default connect(mapStateToProps, mapDispatchToProps)(SearchResults); diff --git a/app/javascript/mastodon/features/compose/index.jsx b/app/javascript/mastodon/features/compose/index.jsx index ce8eb9e05d..83c741fd19 100644 --- a/app/javascript/mastodon/features/compose/index.jsx +++ b/app/javascript/mastodon/features/compose/index.jsx @@ -29,9 +29,9 @@ import { mascot } from '../../initial_state'; import { isMobile } from '../../is_mobile'; import Motion from '../ui/util/optional_motion'; +import { SearchResults } from './components/search_results'; import ComposeFormContainer from './containers/compose_form_container'; import SearchContainer from './containers/search_container'; -import SearchResultsContainer from './containers/search_results_container'; const messages = defineMessages({ start: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, @@ -138,7 +138,7 @@ class Compose extends PureComponent { {({ x }) => (
- +
)}
diff --git a/app/javascript/mastodon/reducers/search.js b/app/javascript/mastodon/reducers/search.js index 72835eb917..7828d49eee 100644 --- a/app/javascript/mastodon/reducers/search.js +++ b/app/javascript/mastodon/reducers/search.js @@ -50,6 +50,7 @@ export default function search(state = initialState, action) { return state.set('hidden', true); case SEARCH_FETCH_REQUEST: return state.withMutations(map => { + map.set('results', ImmutableMap()); map.set('isLoading', true); map.set('submitted', true); map.set('type', action.searchType); From f1a4b4e228ed077692c5bbe6af094308b87c2874 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 08:32:06 -0400 Subject: [PATCH 045/658] Disable `Style/SignalException` cop (#30064) --- .rubocop_todo.yml | 8 -------- lib/devise/strategies/two_factor_ldap_authenticatable.rb | 2 +- lib/devise/strategies/two_factor_pam_authenticatable.rb | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index c2826d718c..e656578149 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -205,14 +205,6 @@ Style/SafeNavigation: Exclude: - 'app/models/concerns/account/finder_concern.rb' -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: only_raise, only_fail, semantic -Style/SignalException: - Exclude: - - 'lib/devise/strategies/two_factor_ldap_authenticatable.rb' - - 'lib/devise/strategies/two_factor_pam_authenticatable.rb' - # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: Mode. Style/StringConcatenation: diff --git a/lib/devise/strategies/two_factor_ldap_authenticatable.rb b/lib/devise/strategies/two_factor_ldap_authenticatable.rb index 065aa2de88..c8258deb16 100644 --- a/lib/devise/strategies/two_factor_ldap_authenticatable.rb +++ b/lib/devise/strategies/two_factor_ldap_authenticatable.rb @@ -16,7 +16,7 @@ module Devise if resource && !resource.otp_required_for_login? success!(resource) else - fail(:invalid) + fail(:invalid) # rubocop:disable Style/SignalException -- method is from Warden::Strategies::Base end end diff --git a/lib/devise/strategies/two_factor_pam_authenticatable.rb b/lib/devise/strategies/two_factor_pam_authenticatable.rb index 5ce723b331..a9db1b6a29 100644 --- a/lib/devise/strategies/two_factor_pam_authenticatable.rb +++ b/lib/devise/strategies/two_factor_pam_authenticatable.rb @@ -15,7 +15,7 @@ module Devise if resource && !resource.otp_required_for_login? success!(resource) else - fail(:invalid) + fail(:invalid) # rubocop:disable Style/SignalException -- method is from Warden::Strategies::Base end end From 924af400da330f8a168afe2b4ffb5dc50dbd8ce9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 29 Apr 2024 08:49:31 -0400 Subject: [PATCH 046/658] Remove unused memoization in `CustomFilter#expires_in` method (#30117) --- app/models/custom_filter.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/custom_filter.rb b/app/models/custom_filter.rb index 94fadc7002..bacf158261 100644 --- a/app/models/custom_filter.rb +++ b/app/models/custom_filter.rb @@ -51,7 +51,6 @@ class CustomFilter < ApplicationRecord after_commit :invalidate_cache! def expires_in - return @expires_in if defined?(@expires_in) return nil if expires_at.nil? EXPIRATION_DURATIONS.find { |expires_in| expires_in.from_now >= expires_at } From f5d6362e9013fa5a1c53ebb7a422916a412a05dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 17:48:34 +0200 Subject: [PATCH 047/658] Update dependency ws to v8.17.0 (#30097) 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 e8f4075e22..878d43d100 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18276,8 +18276,8 @@ __metadata: linkType: hard "ws@npm:^8.11.0, ws@npm:^8.12.1, ws@npm:^8.16.0": - version: 8.16.0 - resolution: "ws@npm:8.16.0" + version: 8.17.0 + resolution: "ws@npm:8.17.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -18286,7 +18286,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10c0/a7783bb421c648b1e622b423409cb2a58ac5839521d2f689e84bc9dc41d59379c692dd405b15a997ea1d4c0c2e5314ad707332d0c558f15232d2bc07c0b4618a + checksum: 10c0/55241ec93a66fdfc4bf4f8bc66c8eb038fda2c7a4ee8f6f157f2ca7dc7aa76aea0c0da0bf3adb2af390074a70a0e45456a2eaf80e581e630b75df10a64b0a990 languageName: node linkType: hard From b8f0a504350a4c30339a755cac0edeadafa9841d Mon Sep 17 00:00:00 2001 From: Shlee Date: Tue, 30 Apr 2024 03:31:14 +1000 Subject: [PATCH 048/658] docker-compose.yml `version` is obsolete (#30120) --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 154754d45f..3f2336f1d9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3' services: db: restart: always From 81f0002e7653b03c65f4c8feeaa4730fdf681b0d Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Tue, 30 Apr 2024 10:48:02 +0200 Subject: [PATCH 049/658] Fix missing destory audit logs for Domain Allows (#30125) --- app/controllers/admin/domain_allows_controller.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/admin/domain_allows_controller.rb b/app/controllers/admin/domain_allows_controller.rb index 31be1978bb..b0f139e3a8 100644 --- a/app/controllers/admin/domain_allows_controller.rb +++ b/app/controllers/admin/domain_allows_controller.rb @@ -25,6 +25,8 @@ class Admin::DomainAllowsController < Admin::BaseController def destroy authorize @domain_allow, :destroy? UnallowDomainService.new.call(@domain_allow) + log_action :destroy, @domain_allow + redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.destroyed_msg') end From f5376c477d142d4c43826b5cea0f9b2f53bf64b7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 10:50:42 +0200 Subject: [PATCH 050/658] Update babel monorepo to v7.24.5 (#30124) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 290 +++++++++++++++++++++++++++--------------------------- 1 file changed, 145 insertions(+), 145 deletions(-) diff --git a/yarn.lock b/yarn.lock index 878d43d100..70395894b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,7 +42,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.24.1, @babel/code-frame@npm:^7.24.2": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.24.2": version: 7.24.2 resolution: "@babel/code-frame@npm:7.24.2" dependencies: @@ -60,37 +60,37 @@ __metadata: linkType: hard "@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1": - version: 7.24.4 - resolution: "@babel/core@npm:7.24.4" + version: 7.24.5 + resolution: "@babel/core@npm:7.24.5" dependencies: "@ampproject/remapping": "npm:^2.2.0" "@babel/code-frame": "npm:^7.24.2" - "@babel/generator": "npm:^7.24.4" + "@babel/generator": "npm:^7.24.5" "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helpers": "npm:^7.24.4" - "@babel/parser": "npm:^7.24.4" + "@babel/helper-module-transforms": "npm:^7.24.5" + "@babel/helpers": "npm:^7.24.5" + "@babel/parser": "npm:^7.24.5" "@babel/template": "npm:^7.24.0" - "@babel/traverse": "npm:^7.24.1" - "@babel/types": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.5" + "@babel/types": "npm:^7.24.5" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10c0/fc136966583e64d6f84f4a676368de6ab4583aa87f867186068655b30ef67f21f8e65a88c6d446a7efd219ad7ffb9185c82e8a90183ee033f6f47b5026641e16 + checksum: 10c0/e26ba810a77bc8e21579a12fc36c79a0a60554404dc9447f2d64eb1f26d181c48d3b97d39d9f158e9911ec7162a8280acfaf2b4b210e975f0dd4bd4dbb1ee159 languageName: node linkType: hard -"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.24.4, @babel/generator@npm:^7.7.2": - version: 7.24.4 - resolution: "@babel/generator@npm:7.24.4" +"@babel/generator@npm:^7.24.5, @babel/generator@npm:^7.7.2": + version: 7.24.5 + resolution: "@babel/generator@npm:7.24.5" dependencies: - "@babel/types": "npm:^7.24.0" + "@babel/types": "npm:^7.24.5" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^2.5.1" - checksum: 10c0/67a1b2f7cc985aaaa11b01e8ddd4fffa4f285837bc7a209738eb8203aa34bdafeb8507ed75fd883ddbabd641a036ca0a8d984e760f28ad4a9d60bff29d0a60bb + checksum: 10c0/0d64f880150e7dfb92ceff2b4ac865f36aa1e295120920246492ffd0146562dabf79ba8699af1c8833f8a7954818d4d146b7b02f808df4d6024fb99f98b2f78d languageName: node linkType: hard @@ -135,22 +135,22 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.4": - version: 7.24.4 - resolution: "@babel/helper-create-class-features-plugin@npm:7.24.4" +"@babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.4, @babel/helper-create-class-features-plugin@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/helper-create-class-features-plugin@npm:7.24.5" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.22.5" "@babel/helper-environment-visitor": "npm:^7.22.20" "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-member-expression-to-functions": "npm:^7.23.0" + "@babel/helper-member-expression-to-functions": "npm:^7.24.5" "@babel/helper-optimise-call-expression": "npm:^7.22.5" "@babel/helper-replace-supers": "npm:^7.24.1" "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/helper-split-export-declaration": "npm:^7.24.5" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/6ebb38375dcd44c79f40008c2de4d023376cf436c135439f15c9c54603c2d6a8ada39b2e07be545da684d9e40b602a0cb0d1670f3877d056deb5f0d786c4bf86 + checksum: 10c0/afc72e8075a249663f8024ef1760de4c0b9252bdde16419ac955fa7e15b8d4096ca1e01f796df4fa8cfdb056708886f60b631ad492242a8e47307974fc305920 languageName: node linkType: hard @@ -208,12 +208,12 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" +"@babel/helper-member-expression-to-functions@npm:^7.23.0, @babel/helper-member-expression-to-functions@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.5" dependencies: - "@babel/types": "npm:^7.23.0" - checksum: 10c0/b810daddf093ffd0802f1429052349ed9ea08ef7d0c56da34ffbcdecbdafac86f95bdea2fe30e0e0e629febc7dd41b56cb5eacc10d1a44336d37b755dac31fa4 + "@babel/types": "npm:^7.24.5" + checksum: 10c0/a3c0276a1ede8648a0e6fd86ad846cd57421d05eddfa29446b8b5a013db650462022b9ec1e65ea32c747d0542d729c80866830697f94fb12d603e87c51f080a5 languageName: node linkType: hard @@ -226,18 +226,18 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/helper-module-transforms@npm:7.23.3" +"@babel/helper-module-transforms@npm:^7.23.3, @babel/helper-module-transforms@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/helper-module-transforms@npm:7.24.5" dependencies: "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-module-imports": "npm:^7.22.15" - "@babel/helper-simple-access": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - "@babel/helper-validator-identifier": "npm:^7.22.20" + "@babel/helper-module-imports": "npm:^7.24.3" + "@babel/helper-simple-access": "npm:^7.24.5" + "@babel/helper-split-export-declaration": "npm:^7.24.5" + "@babel/helper-validator-identifier": "npm:^7.24.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/211e1399d0c4993671e8e5c2b25383f08bee40004ace5404ed4065f0e9258cc85d99c1b82fd456c030ce5cfd4d8f310355b54ef35de9924eabfc3dff1331d946 + checksum: 10c0/6e77d72f62b7e87abaea800ea0bccd4d54cde26485750969f5f493c032eb63251eb50c3522cace557781565d51c1d0c4bcc866407d24becfb109c18fb92c978d languageName: node linkType: hard @@ -250,10 +250,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.24.0 - resolution: "@babel/helper-plugin-utils@npm:7.24.0" - checksum: 10c0/90f41bd1b4dfe7226b1d33a4bb745844c5c63e400f9e4e8bf9103a7ceddd7d425d65333b564d9daba3cebd105985764d51b4bd4c95822b97c2e3ac1201a8a5da +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.24.5 + resolution: "@babel/helper-plugin-utils@npm:7.24.5" + checksum: 10c0/4ae40094e6a2f183281213344f4df60c66b16b19a2bc38d2bb11810a6dc0a0e7ec638957d0e433ff8b615775b8f3cd1b7edbf59440d1b50e73c389fc22913377 languageName: node linkType: hard @@ -283,12 +283,12 @@ __metadata: languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-simple-access@npm:7.22.5" +"@babel/helper-simple-access@npm:^7.22.5, @babel/helper-simple-access@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/helper-simple-access@npm:7.24.5" dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/f0cf81a30ba3d09a625fd50e5a9069e575c5b6719234e04ee74247057f8104beca89ed03e9217b6e9b0493434cedc18c5ecca4cea6244990836f1f893e140369 + "@babel/types": "npm:^7.24.5" + checksum: 10c0/d96a0ab790a400f6c2dcbd9457b9ca74b9ba6d0f67ff9cd5bcc73792c8fbbd0847322a0dddbd8987dd98610ee1637c680938c7d83d3ffce7d06d7519d823d996 languageName: node linkType: hard @@ -301,26 +301,26 @@ __metadata: languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.22.6": - version: 7.22.6 - resolution: "@babel/helper-split-export-declaration@npm:7.22.6" +"@babel/helper-split-export-declaration@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/helper-split-export-declaration@npm:7.24.5" dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/d83e4b623eaa9622c267d3c83583b72f3aac567dc393dda18e559d79187961cb29ae9c57b2664137fc3d19508370b12ec6a81d28af73a50e0846819cb21c6e44 + "@babel/types": "npm:^7.24.5" + checksum: 10c0/d7a812d67d031a348f3fb0e6263ce2dbe6038f81536ba7fb16db385383bcd6542b71833194303bf6d3d0e4f7b6b584c9c8fae8772122e2ce68fc9bdf07f4135d languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/helper-string-parser@npm:7.23.4" - checksum: 10c0/f348d5637ad70b6b54b026d6544bd9040f78d24e7ec245a0fc42293968181f6ae9879c22d89744730d246ce8ec53588f716f102addd4df8bbc79b73ea10004ac +"@babel/helper-string-parser@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/helper-string-parser@npm:7.24.1" + checksum: 10c0/2f9bfcf8d2f9f083785df0501dbab92770111ece2f90d120352fda6dd2a7d47db11b807d111e6f32aa1ba6d763fe2dc6603d153068d672a5d0ad33ca802632b2 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-validator-identifier@npm:7.22.20" - checksum: 10c0/dcad63db345fb110e032de46c3688384b0008a42a4845180ce7cd62b1a9c0507a1bed727c4d1060ed1a03ae57b4d918570259f81724aaac1a5b776056f37504e +"@babel/helper-validator-identifier@npm:^7.22.20, @babel/helper-validator-identifier@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/helper-validator-identifier@npm:7.24.5" + checksum: 10c0/05f957229d89ce95a137d04e27f7d0680d84ae48b6ad830e399db0779341f7d30290f863a93351b4b3bde2166737f73a286ea42856bb07c8ddaa95600d38645c languageName: node linkType: hard @@ -342,14 +342,14 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.24.4": - version: 7.24.4 - resolution: "@babel/helpers@npm:7.24.4" +"@babel/helpers@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/helpers@npm:7.24.5" dependencies: "@babel/template": "npm:^7.24.0" - "@babel/traverse": "npm:^7.24.1" - "@babel/types": "npm:^7.24.0" - checksum: 10c0/747ef62b7fe87de31a2f3c19ff337a86cbb79be2f6c18af63133b614ab5a8f6da5b06ae4b06fb0e71271cb6a27efec6f8b6c9f44c60b8a18777832dc7929e6c5 + "@babel/traverse": "npm:^7.24.5" + "@babel/types": "npm:^7.24.5" + checksum: 10c0/0630b0223c3a9a34027ddc05b3bac54d68d5957f84e92d2d4814b00448a76e12f9188f9c85cfce2011696d82a8ffcbd8189da097c0af0181d32eb27eca34185e languageName: node linkType: hard @@ -365,24 +365,24 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.1, @babel/parser@npm:^7.24.4": - version: 7.24.4 - resolution: "@babel/parser@npm:7.24.4" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/parser@npm:7.24.5" bin: parser: ./bin/babel-parser.js - checksum: 10c0/8381e1efead5069cb7ed2abc3a583f4a86289b2f376c75cecc69f59a8eb36df18274b1886cecf2f97a6a0dff5334b27330f58535be9b3e4e26102cc50e12eac8 + checksum: 10c0/8333a6ad5328bad34fa0e12bcee147c3345ea9a438c0909e7c68c6cfbea43c464834ffd7eabd1cbc1c62df0a558e22ffade9f5b29440833ba7b33d96a71f88c0 languageName: node linkType: hard -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.4": - version: 7.24.4 - resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.4" +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.5" dependencies: "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/9aed453a1a21e4fd29add0b4a2d82a2c6f43a47c80d28411f8327f2a714064bc93a6f622c701d263970e0d72d7901d28f7f51e91ba91a31306efe8f17c411182 + checksum: 10c0/b471972dcc4a3ba32821329a57725e2b563421e975d7ffec7fcabd70af0fced6a50bcc9ed2a8cbd4a9ac7c09cfbf43c7116e82f3b9064b33a22309500b632108 languageName: node linkType: hard @@ -712,14 +712,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.24.4": - version: 7.24.4 - resolution: "@babel/plugin-transform-block-scoping@npm:7.24.4" +"@babel/plugin-transform-block-scoping@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-block-scoping@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/62f55fd1b60a115506e9553c3bf925179b1ab8a42dc31471c4e3ada20573a488b5c5e3317145da352493ef07f1d9750ce1f8a49cb3f39489ac1ab42e5ddc883d + checksum: 10c0/85997fc8179b7d26e8af30865aeb91789f3bc1f0cd5643ed25f25891ff9c071460ec1220599b19070b424a3b902422f682e9b02e515872540173eae2e25f760c languageName: node linkType: hard @@ -748,21 +748,21 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-classes@npm:7.24.1" +"@babel/plugin-transform-classes@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-classes@npm:7.24.5" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.22.5" "@babel/helper-compilation-targets": "npm:^7.23.6" "@babel/helper-environment-visitor": "npm:^7.22.20" "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" "@babel/helper-replace-supers": "npm:^7.24.1" - "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/helper-split-export-declaration": "npm:^7.24.5" globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/586a95826be4d68056fa23d8e6c34353ce2ea59bf3ca8cf62bc784e60964d492d76e1b48760c43fd486ffb65a79d3fed9a4f91289e4f526f88c3b6acc0dfb00e + checksum: 10c0/4affcbb7cb01fa4764c7a4b534c30fd24a4b68e680a2d6e242dd7ca8726490f0f1426c44797deff84a38a162e0629718900c68d28daffe2b12adf5b4194156a7 languageName: node linkType: hard @@ -778,14 +778,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-destructuring@npm:7.24.1" +"@babel/plugin-transform-destructuring@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-destructuring@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/a08e706a9274a699abc3093f38c72d4a5354eac11c44572cc9ea049915b6e03255744297069fd94fcce82380725c5d6b1b11b9a84c0081aa3aa6fc2fdab98ef6 + checksum: 10c0/6a37953a95f04b335bf3e2118fb93f50dd9593c658d1b2f8918a380a2ee30f1b420139eccf7ec3873c86a8208527895fcf6b7e21c0e734a6ad6e5d5042eace4d languageName: node linkType: hard @@ -1017,17 +1017,17 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-object-rest-spread@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.1" +"@babel/plugin-transform-object-rest-spread@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.5" dependencies: "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-transform-parameters": "npm:^7.24.1" + "@babel/plugin-transform-parameters": "npm:^7.24.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e301f1a66b63bafc2bce885305cc88ab30ec875b5e2c7933fb7f9cbf0d954685aa10334ffcecf147ba19d6a1d7ffab37baf4ce871849d395941c56fdb3060f73 + checksum: 10c0/91d7303af9b5744b8f569c1b8e45c9c9322ded05e7ee94e71b9ff2327f0d2c7b5aa87e040697a6baacc2dcb5c5e5e00913087c36f24c006bdaa4f958fd5bfd2d languageName: node linkType: hard @@ -1055,27 +1055,27 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.1" +"@babel/plugin-transform-optional-chaining@npm:^7.24.1, @babel/plugin-transform-optional-chaining@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/b4688795229c9e9ce978eccf979fe515eb4e8d864d2dcd696baa937c8db13e3d46cff664a3cd6119dfe60e261f5d359b10c6783effab7cc91d75d03ad7f43d05 + checksum: 10c0/f4e9446ec69f58f40b7843ce7603cfc50332976e6e794d4ddbe6b24670cd50ebc7766c4e3cbaecf0fbb744e98cbfbb54146f4e966314b1d58511b8bbf3d2722b languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-parameters@npm:7.24.1" +"@babel/plugin-transform-parameters@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-parameters@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/eee8d2f72d3ee0876dc8d85f949f4adf34685cfe36c814ebc20c96315f3891a53d43c764d636b939e34d55e6a6a4af9aa57ed0d7f9439eb5771a07277c669e55 + checksum: 10c0/e08b8c46a24b1b21dde7783cb0aeb56ffe9ef6d6f1795649ce76273657158d3bfa5370c6594200ed7d371983b599c8e194b76108dffed9ab5746fe630ef2e8f5 languageName: node linkType: hard @@ -1091,17 +1091,17 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-private-property-in-object@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.1" +"@babel/plugin-transform-private-property-in-object@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.5" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-create-class-features-plugin": "npm:^7.24.1" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-create-class-features-plugin": "npm:^7.24.5" + "@babel/helper-plugin-utils": "npm:^7.24.5" "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/33d2b9737de7667d7a1b704eef99bfecc6736157d9ea28c2e09010d5f25e33ff841c41d89a4430c5d47f4eb3384e24770fa0ec79600e1e38d6d16e2f9333b4b5 + checksum: 10c0/de7182bfde298e56c08a5d7ee1156f83c9af8c856bbe2248438848846a4ce544e050666bd0482e16a6006195e8be4923abd14650bef51fa0edd7f82014c2efcd languageName: node linkType: hard @@ -1272,14 +1272,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.1" +"@babel/plugin-transform-typeof-symbol@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d392f549bfd13414f59feecdf3fb286f266a3eb9107a9de818e57907bda56eed08d1f6f8e314d09bf99252df026a7fd4d5df839acd45078a777abcebaa9a8593 + checksum: 10c0/5f0b5e33a86b84d89673829ffa2b5f175e102d3d0f45917cda121bc2b3650e1e5bb7a653f8cc1059c5b3a7b2e91e1aafd6623028b96ae752715cc5c2171c96e5 languageName: node linkType: hard @@ -1345,14 +1345,14 @@ __metadata: linkType: hard "@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4": - version: 7.24.4 - resolution: "@babel/preset-env@npm:7.24.4" + version: 7.24.5 + resolution: "@babel/preset-env@npm:7.24.5" dependencies: "@babel/compat-data": "npm:^7.24.4" "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.5" "@babel/helper-validator-option": "npm:^7.23.5" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.4" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.5" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.1" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.1" "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.1" @@ -1379,12 +1379,12 @@ __metadata: "@babel/plugin-transform-async-generator-functions": "npm:^7.24.3" "@babel/plugin-transform-async-to-generator": "npm:^7.24.1" "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.1" - "@babel/plugin-transform-block-scoping": "npm:^7.24.4" + "@babel/plugin-transform-block-scoping": "npm:^7.24.5" "@babel/plugin-transform-class-properties": "npm:^7.24.1" "@babel/plugin-transform-class-static-block": "npm:^7.24.4" - "@babel/plugin-transform-classes": "npm:^7.24.1" + "@babel/plugin-transform-classes": "npm:^7.24.5" "@babel/plugin-transform-computed-properties": "npm:^7.24.1" - "@babel/plugin-transform-destructuring": "npm:^7.24.1" + "@babel/plugin-transform-destructuring": "npm:^7.24.5" "@babel/plugin-transform-dotall-regex": "npm:^7.24.1" "@babel/plugin-transform-duplicate-keys": "npm:^7.24.1" "@babel/plugin-transform-dynamic-import": "npm:^7.24.1" @@ -1404,13 +1404,13 @@ __metadata: "@babel/plugin-transform-new-target": "npm:^7.24.1" "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.1" "@babel/plugin-transform-numeric-separator": "npm:^7.24.1" - "@babel/plugin-transform-object-rest-spread": "npm:^7.24.1" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.5" "@babel/plugin-transform-object-super": "npm:^7.24.1" "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.1" - "@babel/plugin-transform-optional-chaining": "npm:^7.24.1" - "@babel/plugin-transform-parameters": "npm:^7.24.1" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.5" + "@babel/plugin-transform-parameters": "npm:^7.24.5" "@babel/plugin-transform-private-methods": "npm:^7.24.1" - "@babel/plugin-transform-private-property-in-object": "npm:^7.24.1" + "@babel/plugin-transform-private-property-in-object": "npm:^7.24.5" "@babel/plugin-transform-property-literals": "npm:^7.24.1" "@babel/plugin-transform-regenerator": "npm:^7.24.1" "@babel/plugin-transform-reserved-words": "npm:^7.24.1" @@ -1418,7 +1418,7 @@ __metadata: "@babel/plugin-transform-spread": "npm:^7.24.1" "@babel/plugin-transform-sticky-regex": "npm:^7.24.1" "@babel/plugin-transform-template-literals": "npm:^7.24.1" - "@babel/plugin-transform-typeof-symbol": "npm:^7.24.1" + "@babel/plugin-transform-typeof-symbol": "npm:^7.24.5" "@babel/plugin-transform-unicode-escapes": "npm:^7.24.1" "@babel/plugin-transform-unicode-property-regex": "npm:^7.24.1" "@babel/plugin-transform-unicode-regex": "npm:^7.24.1" @@ -1431,7 +1431,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/72a79d0cd38cb26f143509dd0c58db34b5b1ae90116863f55a404f0eb06a64a3cdcb1abd0b6435fafe463bbf55b82ffcf56aedee91e8d37797bf53e4ae74c413 + checksum: 10c0/2cc0edae09205d6409a75d02e53aaa1c590e89adbb7b389019c7b75e4c47b6b63eeb1a816df5c42b672ce410747e7ddc23b6747e8e41a6c95d6fa00c665509e2 languageName: node linkType: hard @@ -1496,11 +1496,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.24.4 - resolution: "@babel/runtime@npm:7.24.4" + version: 7.24.5 + resolution: "@babel/runtime@npm:7.24.5" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/785aff96a3aa8ff97f90958e1e8a7b1d47f793b204b47c6455eaadc3f694f48c97cd5c0a921fe3596d818e71f18106610a164fb0f1c71fd68c622a58269d537c + checksum: 10c0/05730e43e8ba6550eae9fd4fb5e7d9d3cb91140379425abcb2a1ff9cebad518a280d82c4c4b0f57ada26a863106ac54a748d90c775790c0e2cd0ddd85ccdf346 languageName: node linkType: hard @@ -1515,32 +1515,32 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/traverse@npm:7.24.1" +"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/traverse@npm:7.24.5" dependencies: - "@babel/code-frame": "npm:^7.24.1" - "@babel/generator": "npm:^7.24.1" + "@babel/code-frame": "npm:^7.24.2" + "@babel/generator": "npm:^7.24.5" "@babel/helper-environment-visitor": "npm:^7.22.20" "@babel/helper-function-name": "npm:^7.23.0" "@babel/helper-hoist-variables": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - "@babel/parser": "npm:^7.24.1" - "@babel/types": "npm:^7.24.0" + "@babel/helper-split-export-declaration": "npm:^7.24.5" + "@babel/parser": "npm:^7.24.5" + "@babel/types": "npm:^7.24.5" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10c0/c087b918f6823776537ba246136c70e7ce0719fc05361ebcbfd16f4e6f2f6f1f8f4f9167f1d9b675f27d12074839605189cc9d689de20b89a85e7c140f23daab + checksum: 10c0/3f22534bc2b2ed9208e55ef48af3b32939032b23cb9dc4037447cb108640df70bbb0b9fea86e9c58648949fdc2cb14e89aa79ffa3c62a5dd43459a52fe8c01d1 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.24.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.24.0 - resolution: "@babel/types@npm:7.24.0" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.24.5 + resolution: "@babel/types@npm:7.24.5" dependencies: - "@babel/helper-string-parser": "npm:^7.23.4" - "@babel/helper-validator-identifier": "npm:^7.22.20" + "@babel/helper-string-parser": "npm:^7.24.1" + "@babel/helper-validator-identifier": "npm:^7.24.5" to-fast-properties: "npm:^2.0.0" - checksum: 10c0/777a0bb5dbe038ca4c905fdafb1cdb6bdd10fe9d63ce13eca0bd91909363cbad554a53dc1f902004b78c1dcbc742056f877f2c99eeedff647333b1fadf51235d + checksum: 10c0/e1284eb046c5e0451b80220d1200e2327e0a8544a2fe45bb62c952e5fdef7099c603d2336b17b6eac3cc046b7a69bfbce67fe56e1c0ea48cd37c65cb88638f2a languageName: node linkType: hard From 40d7a553d222157aac56b2f5d9e224403e57eec3 Mon Sep 17 00:00:00 2001 From: Shlee Date: Tue, 30 Apr 2024 18:51:39 +1000 Subject: [PATCH 051/658] Minor phrasing on tootcli statuses remove (#30122) --- lib/mastodon/cli/statuses.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/mastodon/cli/statuses.rb b/lib/mastodon/cli/statuses.rb index 57b03c941c..f441dbcd84 100644 --- a/lib/mastodon/cli/statuses.rb +++ b/lib/mastodon/cli/statuses.rb @@ -191,24 +191,24 @@ module Mastodon::CLI def vacuum_and_analyze_statuses if options[:compress_database] - say('Run VACUUM FULL ANALYZE to statuses...') + say('Running "VACUUM FULL ANALYZE statuses"...') ActiveRecord::Base.connection.execute('VACUUM FULL ANALYZE statuses') - say('Run REINDEX to statuses...') + say('Running "REINDEX TABLE statuses"...') ActiveRecord::Base.connection.execute('REINDEX TABLE statuses') else - say('Run ANALYZE to statuses...') + say('Running "ANALYZE statuses"...') ActiveRecord::Base.connection.execute('ANALYZE statuses') end end def vacuum_and_analyze_conversations if options[:compress_database] - say('Run VACUUM FULL ANALYZE to conversations...') + say('Running "VACUUM FULL ANALYZE conversations"...') ActiveRecord::Base.connection.execute('VACUUM FULL ANALYZE conversations') - say('Run REINDEX to conversations...') + say('Running "REINDEX TABLE conversations"...') ActiveRecord::Base.connection.execute('REINDEX TABLE conversations') else - say('Run ANALYZE to conversations...') + say('Running "ANALYZE conversations"...') ActiveRecord::Base.connection.execute('ANALYZE conversations') end end From 56821ed87991eab3609dae53b2e2416053e42fd0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:05:53 +0200 Subject: [PATCH 052/658] New Crowdin Translations (automated) (#30128) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/cy.json | 64 +++++++++++++++++++++++++ app/javascript/mastodon/locales/ia.json | 1 + app/javascript/mastodon/locales/ja.json | 4 +- app/javascript/mastodon/locales/lt.json | 14 ++++++ app/javascript/mastodon/locales/sk.json | 1 + config/locales/cy.yml | 27 ++++++++++- config/locales/doorkeeper.cy.yml | 1 + config/locales/doorkeeper.lt.yml | 1 + config/locales/gl.yml | 1 + config/locales/ia.yml | 5 ++ config/locales/lt.yml | 2 + config/locales/simple_form.cy.yml | 4 ++ config/locales/simple_form.fi.yml | 1 + config/locales/simple_form.gl.yml | 4 ++ config/locales/simple_form.ia.yml | 5 ++ config/locales/simple_form.is.yml | 2 + config/locales/simple_form.lt.yml | 4 ++ config/locales/sv.yml | 1 + 18 files changed, 139 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index d2731b6294..fd8fc74be8 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -89,6 +89,14 @@ "announcement.announcement": "Cyhoeddiad", "attachments_list.unprocessed": "(heb eu prosesu)", "audio.hide": "Cuddio sain", + "block_modal.remote_users_caveat": "Byddwn yn gofyn i'r gweinydd {domain} barchu eich penderfyniad. Fodd bynnag, nid yw cydymffurfiad wedi'i warantu gan y gall rhai gweinyddwyr drin rhwystro mewn ffyrdd gwahanol. Mae'n bosibl y bydd postiadau cyhoeddus yn dal i fod yn weladwy i ddefnyddwyr nad ydynt wedi mewngofnodi.", + "block_modal.show_less": "Dangos llai", + "block_modal.show_more": "Dangos mwy", + "block_modal.they_cant_mention": "Nid ydynt yn gallu eich crybwyll na'ch dilyn.", + "block_modal.they_cant_see_posts": "Nid ydynt yn gallu gweld eich postiadau ac ni fyddwch yn gweld eu rhai hwy.", + "block_modal.they_will_know": "Gallant weld eu bod wedi'u rhwystro.", + "block_modal.title": "Rhwystro defnyddiwr?", + "block_modal.you_wont_see_mentions": "Ni welwch bostiadau sy'n sôn amdanynt.", "boost_modal.combo": "Mae modd pwyso {combo} er mwyn hepgor hyn tro nesa", "bundle_column_error.copy_stacktrace": "Copïo'r adroddiad gwall", "bundle_column_error.error.body": "Nid oedd modd cynhyrchu'r dudalen honno. Gall fod oherwydd gwall yn ein cod neu fater cydnawsedd porwr.", @@ -169,6 +177,7 @@ "confirmations.delete_list.message": "Ydych chi'n siŵr eich bod eisiau dileu'r rhestr hwn am byth?", "confirmations.discard_edit_media.confirm": "Dileu", "confirmations.discard_edit_media.message": "Mae gennych newidiadau heb eu cadw i'r disgrifiad cyfryngau neu'r rhagolwg - eu dileu beth bynnag?", + "confirmations.domain_block.confirm": "Rhwystro gweinydd", "confirmations.domain_block.message": "Ydych chi wir, wir eisiau blocio'r holl {domain}? Fel arfer, mae blocio neu dewi pobl penodol yn broses mwy effeithiol. Fyddwch chi ddim yn gweld cynnwys o'r parth hwnnw mewn ffrydiau cyhoeddus neu yn eich hysbysiadau. Bydd eich dilynwyr o'r parth hwnnw yn cael eu ddileu.", "confirmations.edit.confirm": "Golygu", "confirmations.edit.message": "Bydd golygu nawr yn trosysgrifennu'r neges rydych yn ei ysgrifennu ar hyn o bryd. Ydych chi'n siŵr eich bod eisiau gwneud hyn?", @@ -200,6 +209,27 @@ "dismissable_banner.explore_statuses": "Mae'r rhain yn bostiadau o bob rhan o'r we gymdeithasol sydd ar gynnydd heddiw. Mae postiadau mwy diweddar sydd â mwy o hybiau a ffefrynu'n cael eu graddio'n uwch.", "dismissable_banner.explore_tags": "Mae'r rhain yn hashnodau sydd ar gynnydd ar y we gymdeithasol heddiw. Mae hashnodau sy'n cael eu defnyddio gan fwy o unigolion gwahanol yn cael eu graddio'n uwch.", "dismissable_banner.public_timeline": "Dyma'r postiadau cyhoeddus diweddaraf gan bobl ar y we gymdeithasol y mae pobl ar {domain} yn eu dilyn.", + "domain_block_modal.block": "Rhwystro gweinydd", + "domain_block_modal.block_account_instead": "Rhwystro @{name} yn lle hynny", + "domain_block_modal.they_can_interact_with_old_posts": "Gall pobl o'r gweinydd hwn ryngweithio â'ch hen bostiadau.", + "domain_block_modal.they_cant_follow": "Ni all neb o'r gweinydd hwn eich dilyn.", + "domain_block_modal.they_wont_know": "Fyddan nhw ddim yn gwybod eu bod wedi cael eu rhwystro.", + "domain_block_modal.title": "Rhwystro parth?", + "domain_block_modal.you_will_lose_followers": "Bydd eich holl ddilynwyr o'r gweinydd hwn yn cael eu tynnu.", + "domain_block_modal.you_wont_see_posts": "Fyddwch chi ddim yn gweld postiadau na hysbysiadau gan ddefnyddwyr ar y gweinydd hwn.", + "domain_pill.activitypub_lets_connect": "Mae'n caniatáu ichi gysylltu a rhyngweithio â phobl nid yn unig ar Mastodon, ond ar draws gwahanol apiau cymdeithasol hefyd.", + "domain_pill.activitypub_like_language": "Mae ActivityPub fel yr iaith y mae Mastodon yn ei siarad â rhwydweithiau cymdeithasol eraill.", + "domain_pill.server": "Gweinydd", + "domain_pill.their_handle": "Eu handlen:", + "domain_pill.their_server": "Eu cartref digidol, lle mae eu holl negeseuon yn byw.", + "domain_pill.their_username": "Eu dynodwr unigryw ar eu gweinydd. Mae'n bosibl dod o hyd i ddefnyddwyr gyda'r un enw defnyddiwr ar wahanol weinyddion.", + "domain_pill.username": "Enw Defnyddiwr", + "domain_pill.whats_in_a_handle": "Beth sydd mewn handlen?", + "domain_pill.who_they_are": "Gan fod handlen yn dweud pwy yw rhywun a ble maen nhw, gallwch chi ryngweithio â phobl ar draws gwe gymdeithasol .", + "domain_pill.who_you_are": "Oherwydd bod eich handlen yn dweud pwy ydych chi a ble rydych chi, gall pobl ryngweithio â chi ar draws gwe gymdeithasol .", + "domain_pill.your_handle": "Eich handlen:", + "domain_pill.your_server": "Eich cartref digidol, lle mae'ch holl bostiadau'n byw. Ddim yn hoffi'r un hon? Trosglwyddwch weinyddion ar unrhyw adeg a dewch â'ch dilynwyr hefyd.", + "domain_pill.your_username": "Eich dynodwr unigryw ar y gweinydd hwn. Mae'n bosibl dod o hyd i ddefnyddwyr gyda'r un enw defnyddiwr ar wahanol weinyddion.", "embed.instructions": "Gosodwch y post hwn ar eich gwefan drwy gopïo'r côd isod.", "embed.preview": "Dyma sut olwg fydd arno:", "emoji_button.activity": "Gweithgarwch", @@ -267,6 +297,8 @@ "filter_modal.select_filter.subtitle": "Defnyddiwch gategori sy'n bodoli eisoes neu crëu un newydd", "filter_modal.select_filter.title": "Hidlo'r postiad hwn", "filter_modal.title.status": "Hidlo postiad", + "filtered_notifications_banner.mentions": "{count, plural, one {crybwylliad} other {crybwylliad}}", + "filtered_notifications_banner.pending_requests": "Hysbysiadau gan {count, plural, =0 {neb} one {un person} other {# person}} efallai y gwyddoch amdanyn nhw", "filtered_notifications_banner.title": "Hysbysiadau wedi'u hidlo", "firehose.all": "Popeth", "firehose.local": "Gweinydd hwn", @@ -276,6 +308,8 @@ "follow_requests.unlocked_explanation": "Er nid yw eich cyfrif wedi'i gloi, roedd y staff {domain} yn meddwl efallai hoffech adolygu ceisiadau dilyn o'r cyfrifau rhain wrth law.", "follow_suggestions.curated_suggestion": "Dewis staff", "follow_suggestions.dismiss": "Peidio â dangos hwn eto", + "follow_suggestions.featured_longer": "Wedi'i ddewis â llaw gan dîm {domain}", + "follow_suggestions.friends_of_friends_longer": "Yn boblogaidd ymhlith y bobl rydych chi'n eu dilyn", "follow_suggestions.hints.featured": "Mae'r proffil hwn wedi'i ddewis yn arbennig gan dîm {domain}.", "follow_suggestions.hints.friends_of_friends": "Mae'r proffil hwn yn boblogaidd ymhlith y bobl rydych chi'n eu dilyn.", "follow_suggestions.hints.most_followed": "Mae'r proffil hwn yn un o'r rhai sy'n cael ei ddilyn fwyaf ar {domain}.", @@ -283,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Mae'r proffil hwn yn debyg i'r proffiliau rydych chi wedi'u dilyn yn fwyaf diweddar.", "follow_suggestions.personalized_suggestion": "Awgrym personol", "follow_suggestions.popular_suggestion": "Awgrym poblogaidd", + "follow_suggestions.popular_suggestion_longer": "Yn boblogaidd ar {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Yn debyg i broffiliau y gwnaethoch chi eu dilyn yn ddiweddar", "follow_suggestions.view_all": "Gweld y cyfan", "follow_suggestions.who_to_follow": "Pwy i ddilyn", "followed_tags": "Hashnodau rydych yn eu dilyn", @@ -396,6 +432,15 @@ "loading_indicator.label": "Yn llwytho…", "media_gallery.toggle_visible": "{number, plural, one {Cuddio delwedd} other {Cuddio delwedd}}", "moved_to_account_banner.text": "Ar hyn y bryd, mae eich cyfrif {disabledAccount} wedi ei analluogi am i chi symud i {movedToAccount}.", + "mute_modal.hide_from_notifications": "Cuddio rhag hysbysiadau", + "mute_modal.hide_options": "Cuddio'r dewis", + "mute_modal.indefinite": "Nes i mi eu dad-dewi", + "mute_modal.show_options": "Dangos y dewis", + "mute_modal.they_can_mention_and_follow": "Gallan nhw eich crybwyll a'ch dilyn, ond fyddwch chi ddim yn eu gweld.", + "mute_modal.they_wont_know": "Fyddan nhw ddim yn gwybod eu bod wedi cael eu tawelu.", + "mute_modal.title": "Tewi defnyddiwr?", + "mute_modal.you_wont_see_mentions": "Welwch chi ddim postiadau sy'n sôn amdanyn nhw.", + "mute_modal.you_wont_see_posts": "Gallan nhw weld eich postiadau o hyd, ond fyddwch chi ddim yn gweld eu rhai hwy.", "navigation_bar.about": "Ynghylch", "navigation_bar.advanced_interface": "Agor mewn rhyngwyneb gwe uwch", "navigation_bar.blocks": "Defnyddwyr wedi eu blocio", @@ -428,9 +473,23 @@ "notification.follow": "Dilynodd {name} chi", "notification.follow_request": "Mae {name} wedi gwneud cais i'ch dilyn", "notification.mention": "Crybwyllodd {name} amdanoch chi", + "notification.moderation-warning.learn_more": "Dysgu mwy", + "notification.moderation_warning": "Rydych wedi derbyn rhybudd cymedroli", + "notification.moderation_warning.action_delete_statuses": "Mae rhai o'ch postiadau wedi'u dileu.", + "notification.moderation_warning.action_disable": "Mae eich cyfrif wedi'i analluogi.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Mae rhai o'ch postiadau wedi'u marcio'n sensitif.", + "notification.moderation_warning.action_none": "Mae eich cyfrif wedi derbyn rhybudd cymedroli.", + "notification.moderation_warning.action_sensitive": "Bydd eich postiadau'n cael eu marcio'n sensitif o hyn ymlaen.", + "notification.moderation_warning.action_silence": "Mae eich cyfrif wedi'i gyfyngu.", + "notification.moderation_warning.action_suspend": "Mae eich cyfrif wedi'i hatal.", "notification.own_poll": "Mae eich pleidlais wedi dod i ben", "notification.poll": "Mae pleidlais rydych wedi pleidleisio ynddi wedi dod i ben", "notification.reblog": "Hybodd {name} eich post", + "notification.relationships_severance_event": "Wedi colli cysylltiad â {name}", + "notification.relationships_severance_event.account_suspension": "Mae gweinyddwr o {from} wedi atal {target}, sy'n golygu na allwch dderbyn diweddariadau ganddynt mwyach na rhyngweithio â nhw.", + "notification.relationships_severance_event.domain_block": "Mae gweinyddwr o {from} wedi rhwystro {target}, gan gynnwys {followersCount} o'ch dilynwyr a {followingCount, plural, one {# cyfrif} other {# cyfrif}} arall rydych chi'n ei ddilyn.", + "notification.relationships_severance_event.learn_more": "Dysgu mwy", + "notification.relationships_severance_event.user_domain_block": "Rydych wedi rhwystro {target}, gan ddileu {followersCount} o'ch dilynwyr a {followingCount, plural, one {# cyfrif} other {#cyfrifon}} arall rydych yn ei ddilyn.", "notification.status": "{name} newydd ei bostio", "notification.update": "Golygodd {name} bostiad", "notification_requests.accept": "Derbyn", @@ -443,6 +502,8 @@ "notifications.column_settings.admin.sign_up": "Cofrestriadau newydd:", "notifications.column_settings.alert": "Hysbysiadau bwrdd gwaith", "notifications.column_settings.favourite": "Ffefrynnau:", + "notifications.column_settings.filter_bar.advanced": "Dangos pob categori", + "notifications.column_settings.filter_bar.category": "Bar hidlo cyflym", "notifications.column_settings.follow": "Dilynwyr newydd:", "notifications.column_settings.follow_request": "Ceisiadau dilyn newydd:", "notifications.column_settings.mention": "Crybwylliadau:", @@ -653,9 +714,11 @@ "status.direct": "Crybwyll yn breifat @{name}", "status.direct_indicator": "Crybwyll preifat", "status.edit": "Golygu", + "status.edited": "Golygwyd ddiwethaf {date}", "status.edited_x_times": "Golygwyd {count, plural, one {count} two {count} other {{count} gwaith}}", "status.embed": "Mewnblannu", "status.favourite": "Hoffi", + "status.favourites": "{count, plural, one {ffefryn} other {ffefryn}}", "status.filter": "Hidlo'r postiad hwn", "status.filtered": "Wedi'i hidlo", "status.hide": "Cuddio'r postiad", @@ -676,6 +739,7 @@ "status.reblog": "Hybu", "status.reblog_private": "Hybu i'r gynulleidfa wreiddiol", "status.reblogged_by": "Hybodd {name}", + "status.reblogs": "{count, plural, one {hwb} other {hwb}}", "status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.", "status.redraft": "Dileu ac ailddrafftio", "status.remove_bookmark": "Tynnu nod tudalen", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 73634b99c1..1b969639dc 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -469,6 +469,7 @@ "notification.follow": "{name} te ha sequite", "notification.follow_request": "{name} ha requestate de sequer te", "notification.mention": "{name} te ha mentionate", + "notification.moderation-warning.learn_more": "Apprender plus", "notification.own_poll": "Tu sondage ha finite", "notification.poll": "Un sondage in le qual tu ha votate ha finite", "notification.reblog": "{name} ha impulsate tu message", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 6824a76a31..c11e4a2afd 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -299,7 +299,7 @@ "filter_modal.title.status": "投稿をフィルターする", "filtered_notifications_banner.mentions": "{count, plural, one {メンション} other {メンション}}", "filtered_notifications_banner.pending_requests": "{count, plural, =0 {通知がブロックされているアカウントはありません} other {#アカウントからの通知がブロックされています}}", - "filtered_notifications_banner.title": "ブロック済みの通知", + "filtered_notifications_banner.title": "保留中の通知", "firehose.all": "すべて", "firehose.local": "このサーバー", "firehose.remote": "ほかのサーバー", @@ -486,7 +486,7 @@ "notification_requests.accept": "受け入れる", "notification_requests.dismiss": "無視", "notification_requests.notifications_from": "{name}からの通知", - "notification_requests.title": "ブロック済みの通知", + "notification_requests.title": "保留中の通知", "notifications.clear": "通知を消去", "notifications.clear_confirmation": "本当に通知を消去しますか?", "notifications.column_settings.admin.report": "新しい通報:", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 7b3511cfe1..546b9b7552 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -282,6 +282,7 @@ "filter_modal.select_filter.subtitle": "Naudok esamą kategoriją arba sukurk naują.", "filter_modal.select_filter.title": "Filtruoti šį įrašą", "filter_modal.title.status": "Filtruoti įrašą", + "filtered_notifications_banner.mentions": "{count, plural, one {paminėjimas} few {paminėjimai} many {paminėjimo} other {paminėjimų}}", "firehose.all": "Visi", "firehose.local": "Šis serveris", "firehose.remote": "Kiti serveriai", @@ -290,6 +291,8 @@ "follow_requests.unlocked_explanation": "Nors tavo paskyra neužrakinta, {domain} personalas mano, kad galbūt norėsi rankiniu būdu patikrinti šių paskyrų sekimo prašymus.", "follow_suggestions.curated_suggestion": "Personalo pasirinkimai", "follow_suggestions.dismiss": "Daugiau nerodyti", + "follow_suggestions.featured_longer": "Rankomis atrinkta {domain} komanda", + "follow_suggestions.friends_of_friends_longer": "Populiarus tarp žmonių, kurių seki", "follow_suggestions.hints.featured": "Šį profilį atrinko {domain} komanda.", "follow_suggestions.hints.friends_of_friends": "Šis profilis yra populiarus tarp žmonių, kuriuos seki.", "follow_suggestions.hints.most_followed": "Šis profilis yra vienas iš labiausiai sekamų {domain}.", @@ -297,6 +300,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Šis profilis panašus į profilius, kuriuos neseniai sekei.", "follow_suggestions.personalized_suggestion": "Suasmenintas pasiūlymas", "follow_suggestions.popular_suggestion": "Populiarus pasiūlymas", + "follow_suggestions.popular_suggestion_longer": "Populiarus domene {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Panašūs į profilius, kuriuos neseniai seki", "follow_suggestions.view_all": "Peržiūrėti viską", "follow_suggestions.who_to_follow": "Ką sekti", "followed_tags": "Sekami saitažodžiai", @@ -442,6 +447,15 @@ "notification.follow": "{name} seka tave", "notification.follow_request": "{name} paprašė tave sekti", "notification.mention": "{name} paminėjo tave", + "notification.moderation-warning.learn_more": "Sužinoti daugiau", + "notification.moderation_warning": "Gavai prižiūrėjimo įspėjimą", + "notification.moderation_warning.action_delete_statuses": "Kai kurie tavo įrašai buvo pašalintos.", + "notification.moderation_warning.action_disable": "Tavo paskyra buvo išjungta.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Kai kurie tavo įrašai buvo pažymėtos kaip jautrios.", + "notification.moderation_warning.action_none": "Tavo paskyra gavo prižiūrėjimo įspėjimą.", + "notification.moderation_warning.action_sensitive": "Nuo šiol tavo įrašai bus pažymėti kaip jautrūs.", + "notification.moderation_warning.action_silence": "Tavo paskyra buvo apribota.", + "notification.moderation_warning.action_suspend": "Tavo paskyra buvo sustabdyta.", "notification.own_poll": "Tavo apklausa baigėsi", "notification.poll": "Apklausa, kurioje balsavai, pasibaigė", "notification.reblog": "{name} pakėlė tavo įrašą", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index ea46b82235..e126fdef02 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -246,6 +246,7 @@ "empty_column.list": "Tento zoznam je zatiaľ prázdny. Keď ale členovia tohoto zoznamu uverejnia nové príspevky, objavia sa tu.", "empty_column.lists": "Zatiaľ nemáte žiadne zoznamy. Keď nejaký vytvoríte, zobrazí sa tu.", "empty_column.mutes": "Zatiaľ ste si nikoho nestíšili.", + "empty_column.notification_requests": "Všetko čisté! Nič tu nieje. Keď dostaneš nové oboznámenia, zobrazia sa tu podľa tvojich nastavení.", "empty_column.notifications": "Zatiaľ nemáte žiadne upozornenia. Začnú vám pribúdať, keď s vami začnú interagovať ostatní.", "empty_column.public": "Zatiaľ tu nič nie je. Napíšte niečo verejné alebo začnite sledovať účty z iných serverov, aby tu niečo pribudlo.", "error.unexpected_crash.explanation": "Pre chybu v našom kóde alebo problém s kompatibilitou prehliadača nebolo túto stránku možné zobraziť správne.", diff --git a/config/locales/cy.yml b/config/locales/cy.yml index 93d249cb50..f96068f212 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -645,6 +645,9 @@ cy: actions_description_html: Penderfynwch pa gamau i'w cymryd i ddatrys yr adroddiad hwn. Os byddwch yn cymryd camau cosbol yn erbyn y cyfrif a adroddwyd, bydd hysbysiad e-bost yn cael ei anfon atyn nhw, ac eithrio pan fydd y categori Sbam yn cael ei ddewis. actions_description_remote_html: Penderfynwch pa gamau i'w cymryd i ddatrys yr adroddiad hwn. Bydd hyn ond yn effeithio ar sut mae'ch gweinydd yn cyfathrebu â'r cyfrif hwn o bell ac yn trin ei gynnwys. add_to_report: Ychwanegu rhagor i adroddiad + already_suspended_badges: + local: Wedi atal dros dro ar y gweinydd hwn yn barod + remote: Wedi'i atal eisoes ar eu gweinydd are_you_sure: Ydych chi'n siŵr? assign_to_self: Neilltuo i mi assigned: Cymedrolwr wedi'i neilltuo @@ -804,6 +807,7 @@ cy: desc_html: Mae hyn yn dibynnu ar sgriptiau allanol gan hCaptcha, a all fod yn bryder diogelwch a phreifatrwydd. Yn ogystal, gall hyn wneud y broses gofrestru yn llawer llai hygyrch i rai pobl (yn enwedig yr anabl). Am y rhesymau hyn, ystyriwch fesurau eraill fel cofrestru ar sail cymeradwyaeth neu ar sail gwahoddiad. title: Ei gwneud yn ofynnol i ddefnyddwyr newydd ddatrys CAPTCHA i gadarnhau eu cyfrif content_retention: + danger_zone: Parth perygl preamble: Rheoli sut mae cynnwys sy'n cael ei gynhyrchu gan ddefnyddwyr yn cael ei storio yn Mastodon. title: Cadw cynnwys default_noindex: @@ -1756,13 +1760,26 @@ cy: import: Mewnforio import_and_export: Mewnforio ac allforio migrate: Mudo cyfrif + notifications: Hysbysiadau e-bost preferences: Dewisiadau profile: Proffil cyhoeddus relationships: Yn dilyn a dilynwyr + severed_relationships: Perthynasau wedi'u torri statuses_cleanup: Dileu postiadau'n awtomatig strikes: Rhybuddion cymedroli two_factor_authentication: Dilysu dau-ffactor webauthn_authentication: Allweddi diogelwch + severed_relationships: + download: Llwytho i lawr (%{count}) + event_type: + account_suspension: Atal cyfrif (%{target_name}) + domain_block: Ataliad gweinydd (%{target_name}) + user_domain_block: Rydych wedi rhwystro %{target_name} + lost_followers: Dilynwyr coll + lost_follows: Yn dilyn coll + preamble: Efallai y byddwch yn colli dilynwyr a'r rhai rydych yn eu dilyn pan fyddwch yn rhwystro parth neu pan fydd eich cymedrolwyr yn penderfynu atal gweinydd o bell. Pan fydd hynny'n digwydd, byddwch yn gallu llwytho i lawr rhestrau o berthnasoedd wedi'u torri, i'w harchwilio ac o bosibl eu mewnforio ar weinydd arall. + purged: Mae gwybodaeth am y gweinydd hwn wedi'i dynnu gan weinyddwyr eich gweinydd. + type: Digwyddiad statuses: attached: audio: @@ -1880,6 +1897,7 @@ cy: contrast: Mastodon (Cyferbyniad uchel) default: Mastodon (Tywyll) mastodon-light: Mastodon (Golau) + system: Awtomatig (defnyddio thema system) time: formats: default: "%b %d, %Y, %H:%M" @@ -1992,6 +2010,13 @@ cy: follows_subtitle: Dilynwch gyfrifon adnabyddus follows_title: Pwy i ddilyn follows_view_more: Gweld mwy o bobl i ddilyn + hashtags_recent_count: + few: "%{people} o bobl yn y 2 ddiwrnod diwethaf" + many: "%{people} o bobl yn y 2 ddiwrnod diwethaf" + one: "%{people} person yn ystod y 2 ddiwrnod diwethaf" + other: "%{people} o bobl yn y 2 ddiwrnod diwethaf" + two: "%{people} o bobl yn y 2 ddiwrnod diwethaf" + zero: "%{people} o bobl yn y 2 ddiwrnod diwethaf" hashtags_subtitle: Gweld beth sy'n tueddu dros y 2 ddiwrnod diwethaf hashtags_title: Hashnodau tuedd hashtags_view_more: Gweld mwy o hashnodau tuedd @@ -1999,7 +2024,7 @@ cy: post_step: Dywedwch helo wrth y byd gyda thestun, lluniau, fideos neu arolygon barn. post_title: Creu'ch postiad cyntaf share_action: Rhannu - share_step: Gadewch i'ch ffrindiau wybod sut i ddod o hyd i chi ar Mastodon! + share_step: Gadewch i'ch ffrindiau wybod sut i ddod o hyd i chi ar Mastodon. share_title: Rhannwch eich proffil Mastodon sign_in_action: Mewngofnodi subject: Croeso i Mastodon diff --git a/config/locales/doorkeeper.cy.yml b/config/locales/doorkeeper.cy.yml index e79aa0359f..88cd2b9d53 100644 --- a/config/locales/doorkeeper.cy.yml +++ b/config/locales/doorkeeper.cy.yml @@ -174,6 +174,7 @@ cy: read:filters: gweld eich hidlwyr read:follows: gweld eich dilynwyr read:lists: gweld eich rhestrau + read:me: darllen dim ond manylion elfennol eich cyfrif read:mutes: gweld eich anwybyddiadau read:notifications: gweld eich hysbysiadau read:reports: gweld eich adroddiadau diff --git a/config/locales/doorkeeper.lt.yml b/config/locales/doorkeeper.lt.yml index 6f63e0309d..847f41e816 100644 --- a/config/locales/doorkeeper.lt.yml +++ b/config/locales/doorkeeper.lt.yml @@ -174,6 +174,7 @@ lt: read:filters: matyti tavo filtrus read:follows: matyti tavo sekimus read:lists: matyti tavo sąrašus + read:me: skaityti tik pagrindinę paskyros informaciją read:mutes: matyti tavo nutildymus read:notifications: matyti tavo pranešimus read:reports: matyti tavo ataskaitas diff --git a/config/locales/gl.yml b/config/locales/gl.yml index f36d6783c3..bdf6e5a75f 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -751,6 +751,7 @@ gl: desc_html: Ten dependencia de scripts externos desde hCaptcha, que podería ser un problema de seguridade e privacidade. Ademáis, pode diminuír a accesiblidade para algunhas persoas (principalmente as discapacitadas). Por estas razóns, considera medidas alternativas como o rexistro por convite e a aprobación manual das contas. title: Pedirlle ás novas usuarias resolver un CAPTCHA para confirmar a súa conta content_retention: + danger_zone: Zona perigosa preamble: Controla como se gardan en Mastodon os contidos creados polas usuarias. title: Retención do contido default_noindex: diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 6c99293156..9ec64b1390 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -130,6 +130,7 @@ ia: silenced: Limitate statuses: Messages subscribe: Subscriber + suspend: Suspender suspended: Suspendite title: Contos unblock_email: Disblocar adresse de e-mail @@ -141,6 +142,8 @@ ia: view_domain: Vider summario de dominio action_logs: action_types: + change_email_user: Cambiar e-mail pro le usator + change_role_user: Cambiar le rolo del usator confirm_user: Confirmar le usator create_account_warning: Crear un advertimento create_announcement: Crear annuncio @@ -155,6 +158,7 @@ ia: enable_custom_emoji: Activar emoji personalisate enable_user: Activar le usator promote_user: Promover usator + resend_user: Reinviar message de confirmation reset_password_user: Reinitialisar contrasigno silence_account: Limitar conto unblock_email_account: Disblocar adresse de e-mail @@ -187,6 +191,7 @@ ia: delete: Deler disable: Disactivar disabled: Disactivate + disabled_msg: Emoji disactivate con successo enable: Activar enabled: Activate enabled_msg: Emoji activate con successo diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 9664a4ab57..82fbde6ce1 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -502,6 +502,8 @@ lt: settings: captcha_enabled: desc_html: Tai priklauso nuo hCaptcha išorinių skriptų, kurie gali kelti susirūpinimą dėl saugumo ir privatumo. Be to, dėl to registracijos procesas kai kuriems žmonėms (ypač neįgaliesiems) gali būti gerokai sunkiau prieinami. Dėl šių priežasčių apsvarstyk alternatyvias priemones, pavyzdžiui, patvirtinimu arba kvietimu grindžiamą registraciją. + content_retention: + danger_zone: Pavojinga zona domain_blocks: all: Visiems registrations: diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml index 6b5e8787dd..51a3aac273 100644 --- a/config/locales/simple_form.cy.yml +++ b/config/locales/simple_form.cy.yml @@ -77,10 +77,13 @@ cy: warn: Cuddiwch y cynnwys wedi'i hidlo y tu ôl i rybudd sy'n sôn am deitl yr hidlydd form_admin_settings: activity_api_enabled: Cyfrif o bostiadau a gyhoeddir yn lleol, defnyddwyr gweithredol, a chofrestriadau newydd mewn bwcedi wythnosol + backups_retention_period: Mae gan ddefnyddwyr y gallu i gynhyrchu archifau o'u postiadau i'w llwytho i lawr yn ddiweddarach. Pan gânt eu gosod i werth positif, bydd yr archifau hyn yn cael eu dileu'n awtomatig o'ch storfa ar ôl y nifer penodedig o ddyddiau. bootstrap_timeline_accounts: Bydd y cyfrifon hyn yn cael eu pinio i frig argymhellion dilynol defnyddwyr newydd. closed_registrations_message: Yn cael eu dangos pan fydd cofrestriadau wedi cau + content_cache_retention_period: Bydd yr holl bostiadau gan weinyddion eraill (gan gynnwys hwb ac atebion) yn cael eu dileu ar ôl y nifer penodedig o ddyddiau, heb ystyried unrhyw ryngweithio defnyddiwr lleol â'r postiadau hynny. Mae hyn yn cynnwys postiadau lle mae defnyddiwr lleol wedi ei farcio fel nodau tudalen neu ffefrynnau. Bydd cyfeiriadau preifat rhwng defnyddwyr o wahanol achosion hefyd yn cael eu colli ac yn amhosibl eu hadfer. Mae'r defnydd o'r gosodiad hwn wedi'i fwriadu ar gyfer achosion pwrpas arbennig ac mae'n torri llawer o ddisgwyliadau defnyddwyr pan gaiff ei weithredu at ddibenion cyffredinol. custom_css: Gallwch gymhwyso arddulliau cyfaddas ar fersiwn gwe Mastodon. mascot: Yn diystyru'r darlun yn y rhyngwyneb gwe uwch. + media_cache_retention_period: Mae ffeiliau cyfryngau o bostiadau a wneir gan ddefnyddwyr o bell yn cael eu storio ar eich gweinydd. Pan gaiff ei osod i werth positif, bydd y cyfryngau yn cael eu dileu ar ôl y nifer penodedig o ddyddiau. Os gofynnir am y data cyfryngau ar ôl iddo gael ei ddileu, caiff ei ail-lwytho i lawr, os yw'r cynnwys ffynhonnell yn dal i fod ar gael. Oherwydd cyfyngiadau ar ba mor aml y mae cardiau rhagolwg cyswllt yn pleidleisio i wefannau trydydd parti, argymhellir gosod y gwerth hwn i o leiaf 14 diwrnod, neu ni fydd cardiau rhagolwg cyswllt yn cael eu diweddaru ar alw cyn yr amser hwnnw. peers_api_enabled: Rhestr o enwau parth y mae'r gweinydd hwn wedi dod ar eu traws yn y ffediws. Nid oes unrhyw ddata wedi'i gynnwys yma ynghylch a ydych chi'n ffedereiddio â gweinydd penodol, dim ond bod eich gweinydd yn gwybod amdano. Defnyddir hwn gan wasanaethau sy'n casglu ystadegau ar ffedereiddio mewn ystyr cyffredinol. profile_directory: Mae'r cyfeiriadur proffil yn rhestru'r holl ddefnyddwyr sydd wedi dewis i fod yn ddarganfyddiadwy. require_invite_text: Pan fydd angen cymeradwyaeth â llaw ar gyfer cofrestriadau, gwnewch y “Pam ydych chi am ymuno?” mewnbwn testun yn orfodol yn hytrach na dewisol @@ -240,6 +243,7 @@ cy: backups_retention_period: Cyfnod cadw archif defnyddwyr bootstrap_timeline_accounts: Argymhellwch y cyfrifon hyn i ddefnyddwyr newydd bob amser closed_registrations_message: Neges bersonol pan nad yw cofrestriadau ar gael + content_cache_retention_period: Cyfnod cadw cynnwys o bell custom_css: CSS cyfaddas mascot: Mascot cyfaddas (hen) media_cache_retention_period: Cyfnod cadw storfa cyfryngau diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml index c342dde33e..510b880e3b 100644 --- a/config/locales/simple_form.fi.yml +++ b/config/locales/simple_form.fi.yml @@ -77,6 +77,7 @@ fi: warn: Piilota suodatettu sisältö varoituksen taakse, jossa mainitaan suodattimen nimi form_admin_settings: activity_api_enabled: Paikallisesti julkaistujen julkaisujen, aktiivisten käyttäjien ja rekisteröitymisten viikoittainen määrä + backups_retention_period: Käyttäjillä on mahdollisuus arkistoida julkaisujaan myöhemmin ladattaviksi. Kun tämä on asetettu positiiviseksi arvoksi, nämä arkistot poistetaan automaattisesti asetetun päivien määrän jälkeen. bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuosituslistojen alkuun. closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu custom_css: Voit käyttää mukautettuja tyylejä Mastodonin verkkoversiossa. diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml index bd7c850df4..0433496013 100644 --- a/config/locales/simple_form.gl.yml +++ b/config/locales/simple_form.gl.yml @@ -77,10 +77,13 @@ gl: warn: Agochar o contido filtrado tras un aviso que conteña o nome do filtro form_admin_settings: activity_api_enabled: Conta do número de publicacións locais, usuarias activas, e novos rexistros en acumulados semanais + backups_retention_period: As usuarias poden crear arquivos das súas publicacións para descargalos. Cando se establece un valor positivo, estes arquivos serán borrados automáticamente da túa almacenaxe despois do número de días establecido. bootstrap_timeline_accounts: Estas contas aparecerán fixas na parte superior das recomendacións para as usuarias. closed_registrations_message: Móstrase cando non se admiten novas usuarias + content_cache_retention_period: Todas as publicacións procedentes de outros servidores (incluído promocións e respostas) van ser eliminadas despois do número de días indicado, sen importar as interaccións das usuarias locais con esas publicacións. Esto inclúe publicacións que a usuaria local marcou como favoritas ou incluíu nos marcadores. As mencións privadas entre usuarias de diferentes instancias tamén se eliminarán e non se poderán restablecer. O uso desta ferramenta esta orientado a situacións especiais e estraga moitas das expectativas das usuarias ao implementala cun propósito de uso xeral. custom_css: Podes aplicar deseños personalizados na versión web de Mastodon. mascot: Sobrescribe a ilustración na interface web avanzada. + media_cache_retention_period: Os ficheiros multimedia de publicacións de usuarias remotas están almacenados no teu servidor. Ao establecer un valor positivo, o multimedia vaise eliminar despois do número de días establecido. Se o multimedia fose requerido após ser eliminado entón descargaríase outra vez, se aínda está dispoñible na orixe. Debido a restricións sobre a frecuencia en que o servizo de vista previa trae recursos de terceiras partes, é recomendable establecer este valor polo menos en 14 días, ou as tarxetas de vista previa non se actualizarán baixo demanda para casos anteriores a ese prazo. peers_api_enabled: Unha lista dos nomes de dominio que este servidor atopou no fediverso. Non se inclúen aquí datos acerca de se estás a federar con eles ou non, só que o teu servidor os recoñeceu. Ten utilidade para servizos que recollen estatísticas acerca da federación nun amplo senso. profile_directory: O directorio de perfís inclúe a tódalas usuarias que optaron por ser descubribles. require_invite_text: Cando os rexistros requiren aprobación manual, facer que o texto "Por que te queres rexistrar?" do convite sexa obrigatorio en lugar de optativo @@ -240,6 +243,7 @@ gl: backups_retention_period: Período de retención do arquivo da usuaria bootstrap_timeline_accounts: Recomendar sempre estas contas ás novas usuarias closed_registrations_message: Mensaxe personalizada para cando o rexistro está pechado + content_cache_retention_period: Período de retención de contido remoto custom_css: CSS personalizado mascot: Mascota propia (herdado) media_cache_retention_period: Período de retención da caché multimedia diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index 7012cdb1cd..5e9dda2a13 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -5,8 +5,10 @@ ia: account: note: 'Tu pote @mentionar altere personas o #hashtags.' defaults: + password: Usa al minus 8 characteres setting_display_media_hide_all: Sempre celar le medios setting_display_media_show_all: Sempre monstrar le medios + username: Tu pote usar litteras, numeros e tractos de sublineamento webhook: events: Selige le eventos a inviar url: Ubi le eventos essera inviate @@ -24,7 +26,10 @@ ia: admin_account_action: type: Action types: + disable: Gelar none: Inviar un advertimento + silence: Limitar + suspend: Suspender announcement: text: Annuncio defaults: diff --git a/config/locales/simple_form.is.yml b/config/locales/simple_form.is.yml index a2c437a325..6f3072758c 100644 --- a/config/locales/simple_form.is.yml +++ b/config/locales/simple_form.is.yml @@ -80,8 +80,10 @@ is: backups_retention_period: Notendur hafa kost á að útbúa safnskrár með færslunum sínum til að sækja svo síðar. Þegar þetta er stillt á jákvætt gildi, verður þessum safnskrám eytt sjáfkrafa eftir þeim tiltekna fjölda daga. bootstrap_timeline_accounts: Þessir notendaaðgangar verða festir efst í meðmælum til nýrra notenda um að fylgjast með þeim. closed_registrations_message: Birtist þegar lokað er á nýskráningar + content_cache_retention_period: Öllum færslum af öðrum netþjónum (þar með taldar endurbirtingar og svör) verður eytt eftir uppgefinn fjölda daga, án tillits til gagnvirkni staðværra notenda við þessar færslur. Þetta á einnig við um færslur sem notandinn hefur merkt sem bókamerki eða eftirlæti. Beinar tilvísanir (einkaspjall) milli notenda af mismunandi netþjónum munu einnig tapast og er engin leið til að endurheimta þær. Notkun á þessari stillingu er einungis ætluð sérstilltum netþjónum og mun skemma fyrir notendum ef þetta er sett upp fyrir almenna notkun. custom_css: Þú getur virkjað sérsniðna stíla í vefútgáfu Mastodon. mascot: Þetta tekyr yfir myndskreytinguna í ítarlega vefviðmótinu. + media_cache_retention_period: Myndefnisskrár úr færslum sem gerðar eru af fjartengdum notendum eru geymdar á netþjóninum þínum. Þegar þetta er stillt á jákvætt gildi, verður þessum skrám eytt sjáfkrafa eftir þeim tiltekna fjölda daga. Ef beðið er um myndefnið eftir að því er eytt, mun það verða sótt aftur ef frumgögnin eru ennþá aðgengileg. Vegna takmarkana á hversu oft forskoðunarspjöld tengla eru sótt á utanaðkomandi netþjóna, þá er mælt með því að setja þetta gildi á að minnsta kosti 14 daga, annars gæti mistekist að uppfæra forskoðunarspjöld tengla eftir þörfum fyrir þann tíma. peers_api_enabled: Listi yfir þau lénaheiti sem þessi netþjónn hefur rekist á í skýjasambandinu. Engin gögn eru hér sem gefa til kynna hvort þú sért í sambandi við tiltekinn netþjón, bara að netþjónninn þinn viti um hann. Þetta er notað af þjónustum sem safna tölfræði um skýjasambönd á almennan hátt. profile_directory: Notendamappan telur upp alla þá notendur sem hafa valið að vera uppgötvanlegir. require_invite_text: Þegar nýskráningar krefjast handvirks samþykkis, þá skal gera textann í “Hvers vegna viltu taka þátt?” að kröfu en ekki valkvæðan diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index 00485fc873..f6a3ad9372 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -74,6 +74,9 @@ lt: warn: Slėpti filtruojamą turinį po įspėjimu, paminint filtro pavadinimą form_admin_settings: activity_api_enabled: Vietinių paskelbtų įrašų, aktyvių naudotojų ir naujų registracijų skaičiai kas savaitę + backups_retention_period: Naudotojai gali generuoti savo įrašų archyvus, kuriuos vėliau galės atsisiųsti. Nustačius teigiamą reikšmę, šie archyvai po nurodyto dienų skaičiaus bus automatiškai ištrinti iš saugyklos. + content_cache_retention_period: Visi įrašai iš kitų serverių (įskaitant pakėlimus ir atsakymus) bus ištrinti po nurodyto dienų skaičiaus, neatsižvelgiant į bet kokią vietinio naudotojo sąveiką su tais įrašais. Tai taikoma ir tiems įrašams, kuriuos vietinis naudotojas yra pažymėjęs kaip žymes ar mėgstamus. Privačios paminėjimai tarp naudotojų iš skirtingų instancijų taip pat bus prarastos ir jų bus neįmanoma atkurti. Šis nustatymas skirtas naudoti ypatingos paskirties instancijose, o įgyvendinus jį bendram naudojimui, pažeidžiami daugelio naudotojų lūkesčiai. + media_cache_retention_period: Nuotolinių naudotojų įrašytų įrašų medijos failai talpinami tavo serveryje. Nustačius teigiamą reikšmę, medijos bus ištrinamos po nurodyto dienų skaičiaus. Jei medijos duomenų bus paprašyta po to, kai jie bus ištrinti, jie bus atsiųsti iš naujo, jei šaltinio turinys vis dar prieinamas. Dėl apribojimų, susijusių su nuorodų peržiūros kortelių apklausos dažnumu trečiųjų šalių svetainėse, rekomenduojama nustatyti šią reikšmę ne trumpesnę kaip 14 dienų, kitaip nuorodų peržiūros kortelės nebus atnaujinamos pagal pareikalavimą iki to laiko. peers_api_enabled: Domenų pavadinimų sąrašas, su kuriais šis serveris susidūrė fediverse. Čia nėra duomenų apie tai, ar tu bendrauji su tam tikru serveriu, tik apie tai, kad tavo serveris apie jį žino. Tai naudojama tarnybose, kurios renka federacijos statistiką bendrąja prasme. site_contact_email: Kaip žmonės gali su tavimi susisiekti teisiniais ar pagalbos užklausimais. site_contact_username: Kaip žmonės gali tave pasiekti Mastodon. @@ -145,6 +148,7 @@ lt: form_admin_settings: activity_api_enabled: Skelbti suvestinį statistiką apie naudotojų veiklą per API bootstrap_timeline_accounts: Visada rekomenduoti šias paskyras naujiems naudotojams + content_cache_retention_period: Nuotolinio turinio saugojimo laikotarpis custom_css: Pasirinktinis CSS mascot: Pasirinktinis talismanas (pasenęs) registrations_mode: Kas gali užsiregistruoti diff --git a/config/locales/sv.yml b/config/locales/sv.yml index d078cf7200..11e1fce3fe 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -751,6 +751,7 @@ sv: desc_html: Detta bygger på externa skript från hCaptcha vilket kan vara ett säkerhets- och integritetsproblem. Dessutom,kan detta göra registreringsprocessen betydligt mindre tillgänglig för vissa personer (särskilt funktionsnedsatta). Av dessa skäl bör du överväga alternativa åtgärder såsom godkänningsbaserad eller inbjudningsbaserad registrering. title: Kräv att nya användare löser en CAPTCHA för att erkänna sitt konto content_retention: + danger_zone: Farozon preamble: Kontrollera hur användargenererat innehåll lagras i Mastodon. title: Bibehållande av innehåll default_noindex: From f3ea90b89eea93d0a4d86ac1eef9ae52f93a61fd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:12:25 +0200 Subject: [PATCH 053/658] Update workbox monorepo to v7.1.0 (#30047) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 357 +++++++++++++++++++++++++++++------------------------- 1 file changed, 195 insertions(+), 162 deletions(-) diff --git a/yarn.lock b/yarn.lock index 70395894b8..5e83223a2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -59,7 +59,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1": +"@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1, @babel/core@npm:^7.24.4": version: 7.24.5 resolution: "@babel/core@npm:7.24.5" dependencies: @@ -3073,19 +3073,22 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-node-resolve@npm:^11.2.1": - version: 11.2.1 - resolution: "@rollup/plugin-node-resolve@npm:11.2.1" +"@rollup/plugin-node-resolve@npm:^15.2.3": + version: 15.2.3 + resolution: "@rollup/plugin-node-resolve@npm:15.2.3" dependencies: - "@rollup/pluginutils": "npm:^3.1.0" - "@types/resolve": "npm:1.17.1" - builtin-modules: "npm:^3.1.0" + "@rollup/pluginutils": "npm:^5.0.1" + "@types/resolve": "npm:1.20.2" deepmerge: "npm:^4.2.2" + is-builtin-module: "npm:^3.2.1" is-module: "npm:^1.0.0" - resolve: "npm:^1.19.0" + resolve: "npm:^1.22.1" peerDependencies: - rollup: ^1.20.0||^2.0.0 - checksum: 10c0/a8226b01352ee1f7133b1b59b3906267e11c99020a55e3b7a313e03889f790d1cd94e7f7769d3963261e897c3265082533ba595976f8e3f08cf70aa88bf1ddd7 + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/598c15615086f26e28c4b3dbf966682af7fb0e5bc277cc4e57f559668a3be675a63ab261eb34729ce9569c3a51342c48863e50b5efe02e0fc1571828f0113f9d languageName: node linkType: hard @@ -3101,6 +3104,22 @@ __metadata: languageName: node linkType: hard +"@rollup/plugin-terser@npm:^0.4.3": + version: 0.4.4 + resolution: "@rollup/plugin-terser@npm:0.4.4" + dependencies: + serialize-javascript: "npm:^6.0.1" + smob: "npm:^1.0.0" + terser: "npm:^5.17.4" + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/b9cb6c8f02ac1c1344019e9fb854321b74f880efebc41b6bdd84f18331fce0f4a2aadcdb481042245cd3f409b429ac363af71f9efec4a2024731d67d32af36ee + languageName: node + linkType: hard + "@rollup/pluginutils@npm:^3.1.0": version: 3.1.0 resolution: "@rollup/pluginutils@npm:3.1.0" @@ -3114,6 +3133,22 @@ __metadata: languageName: node linkType: hard +"@rollup/pluginutils@npm:^5.0.1": + version: 5.1.0 + resolution: "@rollup/pluginutils@npm:5.1.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-walker: "npm:^2.0.2" + picomatch: "npm:^2.3.1" + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/c7bed15711f942d6fdd3470fef4105b73991f99a478605e13d41888963330a6f9e32be37e6ddb13f012bc7673ff5e54f06f59fd47109436c1c513986a8a7612d + languageName: node + linkType: hard + "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -3470,10 +3505,10 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*": - version: 1.0.3 - resolution: "@types/estree@npm:1.0.3" - checksum: 10c0/5171f467fdd77852e28d7eec575222bc6c900e117a44e916a5ff65807ae8e1ed15f57d21e8954d6bd532e37c49a8ecfee730fcb152b7b44234d38681978b2caa +"@types/estree@npm:*, @types/estree@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: 10c0/b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d languageName: node linkType: hard @@ -3889,12 +3924,10 @@ __metadata: languageName: node linkType: hard -"@types/resolve@npm:1.17.1": - version: 1.17.1 - resolution: "@types/resolve@npm:1.17.1" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/6eeb9c27d99bf4b393bf168d43208f63e78cefca5644662a0bdb2bdbf8352386f4f3aca66add138fc41bce5f66fd48a0de430a1473f11b612fbed0375ae78031 +"@types/resolve@npm:1.20.2": + version: 1.20.2 + resolution: "@types/resolve@npm:1.20.2" + checksum: 10c0/c5b7e1770feb5ccfb6802f6ad82a7b0d50874c99331e0c9b259e415e55a38d7a86ad0901c57665d93f75938be2a6a0bc9aa06c9749192cadb2e4512800bbc6e6 languageName: node linkType: hard @@ -5662,7 +5695,7 @@ __metadata: languageName: node linkType: hard -"builtin-modules@npm:^3.1.0, builtin-modules@npm:^3.3.0": +"builtin-modules@npm:^3.3.0": version: 3.3.0 resolution: "builtin-modules@npm:3.3.0" checksum: 10c0/2cb3448b4f7306dc853632a4fcddc95e8d4e4b9868c139400027b71938fc6806d4ff44007deffb362ac85724bd40c2c6452fb6a0aa4531650eeddb98d8e5ee8a @@ -7987,6 +8020,13 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^2.0.2": + version: 2.0.2 + resolution: "estree-walker@npm:2.0.2" + checksum: 10c0/53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -10744,7 +10784,7 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^26.2.1, jest-worker@npm:^26.5.0": +"jest-worker@npm:^26.5.0": version: 26.6.2 resolution: "jest-worker@npm:26.6.2" dependencies: @@ -15023,7 +15063,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.4": +"resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -15049,7 +15089,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -15156,20 +15196,6 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-terser@npm:^7.0.0": - version: 7.0.2 - resolution: "rollup-plugin-terser@npm:7.0.2" - dependencies: - "@babel/code-frame": "npm:^7.10.4" - jest-worker: "npm:^26.2.1" - serialize-javascript: "npm:^4.0.0" - terser: "npm:^5.0.0" - peerDependencies: - rollup: ^2.0.0 - checksum: 10c0/f79b851c6f7b06555d3a8ce7a4e32abd2b7cb8318e89fb8db73e662fa6e3af1a59920e881d111efc65a7437fd9582b61b1f4859b6fd839ba948616829d92432d - languageName: node - linkType: hard - "rollup@npm:^2.43.1": version: 2.79.1 resolution: "rollup@npm:2.79.1" @@ -15439,15 +15465,6 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^4.0.0": - version: 4.0.0 - resolution: "serialize-javascript@npm:4.0.0" - dependencies: - randombytes: "npm:^2.1.0" - checksum: 10c0/510dfe7f0311c0b2f7ab06311afa1668ba2969ab2f1faaac0a4924ede76b7f22ba85cfdeaa0052ec5a047bca42c8cd8ac8df8f0efe52f9bd290b3a39ae69fe9d - languageName: node - linkType: hard - "serialize-javascript@npm:^5.0.1": version: 5.0.1 resolution: "serialize-javascript@npm:5.0.1" @@ -15457,6 +15474,15 @@ __metadata: languageName: node linkType: hard +"serialize-javascript@npm:^6.0.1": + version: 6.0.2 + resolution: "serialize-javascript@npm:6.0.2" + dependencies: + randombytes: "npm:^2.1.0" + checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 + languageName: node + linkType: hard + "serve-index@npm:^1.9.1": version: 1.9.1 resolution: "serve-index@npm:1.9.1" @@ -15697,6 +15723,13 @@ __metadata: languageName: node linkType: hard +"smob@npm:^1.0.0": + version: 1.5.0 + resolution: "smob@npm:1.5.0" + checksum: 10c0/a1067f23265812de8357ed27312101af49b89129eb973e3f26ab5856ea774f88cace13342e66e32470f933ccfa916e0e9d0f7ca8bbd4f92dfab2af45c15956c2 + languageName: node + linkType: hard + "snapdragon-node@npm:^2.0.1": version: 2.1.1 resolution: "snapdragon-node@npm:2.1.1" @@ -16672,9 +16705,9 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.0.0, terser@npm:^5.3.4": - version: 5.19.4 - resolution: "terser@npm:5.19.4" +"terser@npm:^5.17.4, terser@npm:^5.3.4": + version: 5.31.0 + resolution: "terser@npm:5.31.0" dependencies: "@jridgewell/source-map": "npm:^0.3.3" acorn: "npm:^8.8.2" @@ -16682,7 +16715,7 @@ __metadata: source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: 10c0/39c6687609f5b9061f2fb82bee02d2f9d7756fcb5bd50c67da1482f52cf5977e03e0c5df5cb4ce17e549428024c8859075137c461ec4a9ae8cf91a505759255a + checksum: 10c0/cb127a579b03fb9dcee0d293ff24814deedcd430f447933b618e8593b7454f615b5c8493c68e86a4b0188769d5ea2af5251b5d507edb208114f7e8aebdc7c850 languageName: node linkType: hard @@ -17975,36 +18008,37 @@ __metadata: languageName: node linkType: hard -"workbox-background-sync@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-background-sync@npm:7.0.0" +"workbox-background-sync@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-background-sync@npm:7.1.0" dependencies: idb: "npm:^7.0.1" - workbox-core: "npm:7.0.0" - checksum: 10c0/91eb064c608cfb4cf7aa4f062215d8217a99b93d67c4ae571e5abdda1b020c5ab45c7bddab99cb77d334aae8d259f0fe91b7c42ee6e7ad10db32b4a971991489 + workbox-core: "npm:7.1.0" + checksum: 10c0/9538c49a377d8eb06acee3848fbca09bac1940a2ca9e904fed765c39aa32f77c20d72c3ba6fa1eb47bee81289b1d527556a1cd3e02728960a4c40400ce6d0e91 languageName: node linkType: hard -"workbox-broadcast-update@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-broadcast-update@npm:7.0.0" +"workbox-broadcast-update@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-broadcast-update@npm:7.1.0" dependencies: - workbox-core: "npm:7.0.0" - checksum: 10c0/3c3a6e1e72c19d2971d187297b99b242f304b1ec442f6f1ec84ea9c6e125dc01cd626d51e6ecf1c8d89226e6a286dccaa9f950bd5ef6183518af10ba0f4f524e + workbox-core: "npm:7.1.0" + checksum: 10c0/4a6e201cedcbc11b9d2f63f63477ba4564a35ce07bd54640198db6ff6a3b8347a65e0b4973c8f8463e8a622fd1ad93d7b3bab42338608811d23c7db01fef475e languageName: node linkType: hard -"workbox-build@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-build@npm:7.0.0" +"workbox-build@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-build@npm:7.1.0" dependencies: "@apideck/better-ajv-errors": "npm:^0.3.1" - "@babel/core": "npm:^7.11.1" + "@babel/core": "npm:^7.24.4" "@babel/preset-env": "npm:^7.11.0" "@babel/runtime": "npm:^7.11.2" "@rollup/plugin-babel": "npm:^5.2.0" - "@rollup/plugin-node-resolve": "npm:^11.2.1" + "@rollup/plugin-node-resolve": "npm:^15.2.3" "@rollup/plugin-replace": "npm:^2.4.1" + "@rollup/plugin-terser": "npm:^0.4.3" "@surma/rollup-plugin-off-main-thread": "npm:^2.2.3" ajv: "npm:^8.6.0" common-tags: "npm:^1.8.0" @@ -18014,169 +18048,168 @@ __metadata: lodash: "npm:^4.17.20" pretty-bytes: "npm:^5.3.0" rollup: "npm:^2.43.1" - rollup-plugin-terser: "npm:^7.0.0" source-map: "npm:^0.8.0-beta.0" stringify-object: "npm:^3.3.0" strip-comments: "npm:^2.0.1" tempy: "npm:^0.6.0" upath: "npm:^1.2.0" - workbox-background-sync: "npm:7.0.0" - workbox-broadcast-update: "npm:7.0.0" - workbox-cacheable-response: "npm:7.0.0" - workbox-core: "npm:7.0.0" - workbox-expiration: "npm:7.0.0" - workbox-google-analytics: "npm:7.0.0" - workbox-navigation-preload: "npm:7.0.0" - workbox-precaching: "npm:7.0.0" - workbox-range-requests: "npm:7.0.0" - workbox-recipes: "npm:7.0.0" - workbox-routing: "npm:7.0.0" - workbox-strategies: "npm:7.0.0" - workbox-streams: "npm:7.0.0" - workbox-sw: "npm:7.0.0" - workbox-window: "npm:7.0.0" - checksum: 10c0/a090aeee836f59d42ca9eda8b82aa5a0ee8f4ce3f3095b6fcbe157a9a154c492e4ba86b5c4d6aa50ef7c37ea1c38c965442b56d1404911fd0351d0fc9a859a3c + workbox-background-sync: "npm:7.1.0" + workbox-broadcast-update: "npm:7.1.0" + workbox-cacheable-response: "npm:7.1.0" + workbox-core: "npm:7.1.0" + workbox-expiration: "npm:7.1.0" + workbox-google-analytics: "npm:7.1.0" + workbox-navigation-preload: "npm:7.1.0" + workbox-precaching: "npm:7.1.0" + workbox-range-requests: "npm:7.1.0" + workbox-recipes: "npm:7.1.0" + workbox-routing: "npm:7.1.0" + workbox-strategies: "npm:7.1.0" + workbox-streams: "npm:7.1.0" + workbox-sw: "npm:7.1.0" + workbox-window: "npm:7.1.0" + checksum: 10c0/c482fde713bad582bd7d4861113d7367ab4722eba9c102864c71048815792c623e9117a8f79957e0388d0c08e8303962d1fb23931456da73909e87d06638d101 languageName: node linkType: hard -"workbox-cacheable-response@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-cacheable-response@npm:7.0.0" +"workbox-cacheable-response@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-cacheable-response@npm:7.1.0" dependencies: - workbox-core: "npm:7.0.0" - checksum: 10c0/ddf123b3461070e215af51d88c672f3302b540b93ecf61ad5f3853f0a997194973eedb2c9ed21e849b7419f68804ef8a8d876dced3836a7eb2c697099e3d408f + workbox-core: "npm:7.1.0" + checksum: 10c0/52ea73bb184c9ef9280cc8f00a1ab7d103d495e12a7a6378fae02fd0aa1a9b893aac5d8074f14ed8c198527123e4401f4703fbfd2be98e184ca783b9216cb4c5 languageName: node linkType: hard -"workbox-core@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-core@npm:7.0.0" - checksum: 10c0/aaaf7b66978456bf5d6a90b1068b5acd82bf451f4a23c5a416201524b50ea4e0bc62a01365499bc088b4c18cddc513fdebbe8b048ab15aff960fe7cbbf55d5bd +"workbox-core@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-core@npm:7.1.0" + checksum: 10c0/fb0b6e23a52e085da00b7a74b1f1854f06c695eb2bd4c244aa335165f59156a4febb4f116b9893b9fb7e0e8bac092d32eecceb4d00f930a93f64737cb2be9531 languageName: node linkType: hard -"workbox-expiration@npm:7.0.0, workbox-expiration@npm:^7.0.0": - version: 7.0.0 - resolution: "workbox-expiration@npm:7.0.0" +"workbox-expiration@npm:7.1.0, workbox-expiration@npm:^7.0.0": + version: 7.1.0 + resolution: "workbox-expiration@npm:7.1.0" dependencies: idb: "npm:^7.0.1" - workbox-core: "npm:7.0.0" - checksum: 10c0/990a6c2c9b177d796c012b0112913621e41b283e2736d83acb58cb9645591ddc7a6aef585145c5686f9b071d73ce12b4b1887765754624322545b0f4125d649f + workbox-core: "npm:7.1.0" + checksum: 10c0/669d76f87c1550ce9b425232c3202a26fdea4c4c9bdc1b71c1cee741a5d011423098994452e508576174d3c0b4bec0f4b35012b6d7257e300684c87fdddb7949 languageName: node linkType: hard -"workbox-google-analytics@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-google-analytics@npm:7.0.0" +"workbox-google-analytics@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-google-analytics@npm:7.1.0" dependencies: - workbox-background-sync: "npm:7.0.0" - workbox-core: "npm:7.0.0" - workbox-routing: "npm:7.0.0" - workbox-strategies: "npm:7.0.0" - checksum: 10c0/7656ab4bff15fbcbc7f546d86628ccbc74736a99139ec70a166c465fc4ff59656aecd44cc0aef45b4690fd88a4980d6c9f27ce8c6606fd12d026162259a8069d + workbox-background-sync: "npm:7.1.0" + workbox-core: "npm:7.1.0" + workbox-routing: "npm:7.1.0" + workbox-strategies: "npm:7.1.0" + checksum: 10c0/4178d94fb7f3f7b789f117c104b2ff33945256dc550418b0e9c81130c1e2c2bcd72ec6a1661d91326c04de360e6592edd505f0e2142e8e1043fe0c45f9c1a3fe languageName: node linkType: hard -"workbox-navigation-preload@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-navigation-preload@npm:7.0.0" +"workbox-navigation-preload@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-navigation-preload@npm:7.1.0" dependencies: - workbox-core: "npm:7.0.0" - checksum: 10c0/f29ac8364c7f7f392daa1f886134adc780057199b218ab6c6eef298841b8825d6cbc4bc88e655299929bdf14c700edfb9f217ca5c0b46094627247528f655011 + workbox-core: "npm:7.1.0" + checksum: 10c0/b667a3ba0cae4d43a53a6e211f0f33f6ebc1d9fec6cbb93de83f72a37b81cc39d887b969db9b1cd5c396a1ce34636c89c3b157cc64a5265635d0b274e362db0e languageName: node linkType: hard -"workbox-precaching@npm:7.0.0, workbox-precaching@npm:^7.0.0": - version: 7.0.0 - resolution: "workbox-precaching@npm:7.0.0" +"workbox-precaching@npm:7.1.0, workbox-precaching@npm:^7.0.0": + version: 7.1.0 + resolution: "workbox-precaching@npm:7.1.0" dependencies: - workbox-core: "npm:7.0.0" - workbox-routing: "npm:7.0.0" - workbox-strategies: "npm:7.0.0" - checksum: 10c0/1b47cb151bb6ec7442b2dc8981203feff22527a4383510f2399730338b620ef0d03076bd3dbc1eb9a05272d5d6f4803fb4262f320bf5645f0818981e91077f39 + workbox-core: "npm:7.1.0" + workbox-routing: "npm:7.1.0" + workbox-strategies: "npm:7.1.0" + checksum: 10c0/53b2d0a658109b4d83ee2b1913f884ee1c757a12b8931a7102272bd1e228d29f9430e7d060f328f465bca2aa24bf0719d026eef4f4d21395fa1f678f8d6a3c06 languageName: node linkType: hard -"workbox-range-requests@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-range-requests@npm:7.0.0" +"workbox-range-requests@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-range-requests@npm:7.1.0" dependencies: - workbox-core: "npm:7.0.0" - checksum: 10c0/909f0ed7a176e5dc55692792825e67b577dacf1015a3f3775389fcec34ff5b3441b15595109455fe226f0bc4dce4789a7c86e5e9c5963c13b4d6482f6d01d44f + workbox-core: "npm:7.1.0" + checksum: 10c0/bf4aa597d04cbb533796af64f4006a1f472f8a14ea91f96fe37b2d5e63ffe86dcb944dab9a41317e69d368d83bee20f03ff32b339ae5addef50f325703ad4b77 languageName: node linkType: hard -"workbox-recipes@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-recipes@npm:7.0.0" +"workbox-recipes@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-recipes@npm:7.1.0" dependencies: - workbox-cacheable-response: "npm:7.0.0" - workbox-core: "npm:7.0.0" - workbox-expiration: "npm:7.0.0" - workbox-precaching: "npm:7.0.0" - workbox-routing: "npm:7.0.0" - workbox-strategies: "npm:7.0.0" - checksum: 10c0/c024141f24b0778355bdfbfe2b4a24a3f74e279f6f7541635758533e79318e15986f9f556a899c97717a9c25a1738d9e112d17dd36aa19cebf901462ebeeb8e4 + workbox-cacheable-response: "npm:7.1.0" + workbox-core: "npm:7.1.0" + workbox-expiration: "npm:7.1.0" + workbox-precaching: "npm:7.1.0" + workbox-routing: "npm:7.1.0" + workbox-strategies: "npm:7.1.0" + checksum: 10c0/5a8c2444f6338c6092be87cc6fd69c8b0cbb413bfc0a11a8f10961bfb2b8059359c4be0264ffa0c01deff3ab5dba15bbcf61d4dedbc93d8bfe1f8a2841b1657c languageName: node linkType: hard -"workbox-routing@npm:7.0.0, workbox-routing@npm:^7.0.0": - version: 7.0.0 - resolution: "workbox-routing@npm:7.0.0" +"workbox-routing@npm:7.1.0, workbox-routing@npm:^7.0.0": + version: 7.1.0 + resolution: "workbox-routing@npm:7.1.0" dependencies: - workbox-core: "npm:7.0.0" - checksum: 10c0/74ad651a0643506cfd3ca51eee754f5fe34e3f1460e6b772ed213e0422028cf002d70f91da32d13261bc5ee2160527ffb5436ac209fdbe8d0e7071784aa65190 + workbox-core: "npm:7.1.0" + checksum: 10c0/efd630fff594bd50276770840bce274660972587e79c097a9f1a84e8347351736aac13f11c6d7655ff550b13195d370d5c3b81a075bf452f358fc144ee868ad9 languageName: node linkType: hard -"workbox-strategies@npm:7.0.0, workbox-strategies@npm:^7.0.0": - version: 7.0.0 - resolution: "workbox-strategies@npm:7.0.0" +"workbox-strategies@npm:7.1.0, workbox-strategies@npm:^7.0.0": + version: 7.1.0 + resolution: "workbox-strategies@npm:7.1.0" dependencies: - workbox-core: "npm:7.0.0" - checksum: 10c0/4fe122b80e547b347bedf187aeb2c2eb34efc3fbde2733b7709530cccb6b6e03b29adcbccecf301e4fcaad0d5cd4a74e1e704f769d949c32439dca358130a613 + workbox-core: "npm:7.1.0" + checksum: 10c0/b08712a69b1b13e354345cc228c29f0c759043f7ca7cf6ce9b82fe79c9d423142bfa4a118f91f1a57054047a730127fa4474d59d9306fb2ed42fe9ef568be01a languageName: node linkType: hard -"workbox-streams@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-streams@npm:7.0.0" +"workbox-streams@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-streams@npm:7.1.0" dependencies: - workbox-core: "npm:7.0.0" - workbox-routing: "npm:7.0.0" - checksum: 10c0/9a1a9b8200f5b315523ac49c61a9b88791009377bbdedd44cf19c4b2258e710bd2fbc6f74ef53b72db7849da7ce9965ced5983f167785ccfc7efa1df761e3371 + workbox-core: "npm:7.1.0" + workbox-routing: "npm:7.1.0" + checksum: 10c0/1d75c046fcb7b25e1cf85457e3610309dd5513f68752ef333529fcf155df2114b72f3d6f416bb68393e51b5396e3f6df7171e8e2889d0e9e1805e315754b771e languageName: node linkType: hard -"workbox-sw@npm:7.0.0": - version: 7.0.0 - resolution: "workbox-sw@npm:7.0.0" - checksum: 10c0/06d9713398ca92d8b2cad70a7d302825ec7650e05e2e0c8e68f453442fdf9a9227350c856484f7b649df6cb429cc03a103f8ecd9596e83bfa52e845bf25ffbcd +"workbox-sw@npm:7.1.0": + version: 7.1.0 + resolution: "workbox-sw@npm:7.1.0" + checksum: 10c0/2084f1b58c8509d7ca53ce8a13d93e57d1f13307e0279fedc87942e83c8cb96bc2e5ed3992a89af6245ad2a66897a92908cb60d0717fb90492056eb6fbf20dc6 languageName: node linkType: hard "workbox-webpack-plugin@npm:^7.0.0": - version: 7.0.0 - resolution: "workbox-webpack-plugin@npm:7.0.0" + version: 7.1.0 + resolution: "workbox-webpack-plugin@npm:7.1.0" dependencies: fast-json-stable-stringify: "npm:^2.1.0" pretty-bytes: "npm:^5.4.1" upath: "npm:^1.2.0" webpack-sources: "npm:^1.4.3" - workbox-build: "npm:7.0.0" + workbox-build: "npm:7.1.0" peerDependencies: - webpack: ^4.4.0 || ^5.9.0 - checksum: 10c0/3d585842bb6f801db5571e4d3e5c1d7c141f91d9ba2ed0c36b617d86a00b37bdefc055e6cc981c557f21f878ff4a9cf8b82e4b0b31084ddf4d9d149673ce8882 + webpack: ^4.4.0 || ^5.91.0 + checksum: 10c0/516fa68a6a6958ee1560299dd1146032dda68474a2ab01643cbde78fc65b75a3157aef60cb45dcc1984cc458ce44d4e3090cda08dd7cefd0952351270e963a00 languageName: node linkType: hard -"workbox-window@npm:7.0.0, workbox-window@npm:^7.0.0": - version: 7.0.0 - resolution: "workbox-window@npm:7.0.0" +"workbox-window@npm:7.1.0, workbox-window@npm:^7.0.0": + version: 7.1.0 + resolution: "workbox-window@npm:7.1.0" dependencies: "@types/trusted-types": "npm:^2.0.2" - workbox-core: "npm:7.0.0" - checksum: 10c0/8070fb80734a8543248ed6e3b186b8d3ee64419400a6d6d75f78809c44bf16321c5d9739bdf60ee62f631461ebb67a8a7dd78192504678d00bf2a9d3683f1324 + workbox-core: "npm:7.1.0" + checksum: 10c0/c989a6e3a0488f049eead3892f8249387604fb04898aa79d0cf14cd7b684f0758f1edf1996745f4755bd30c31c449f628803e507d39b2ea91cc9c36f7d5e9c72 languageName: node linkType: hard From 75470f1256cbc962be5ed7d92f4e522146cfaac5 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 30 Apr 2024 09:00:39 -0400 Subject: [PATCH 054/658] Use implicit dotenv load (#30121) --- config/application.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/application.rb b/config/application.rb index 1b38789927..402c7f0614 100644 --- a/config/application.rb +++ b/config/application.rb @@ -51,12 +51,8 @@ require_relative '../lib/active_record/database_tasks_extensions' require_relative '../lib/active_record/batches' require_relative '../lib/simple_navigation/item_extensions' -Dotenv::Rails.load - Bundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true' -require_relative '../lib/mastodon/redis_config' - module Mastodon class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. @@ -98,6 +94,10 @@ module Mastodon app.deprecators[:mastodon] = ActiveSupport::Deprecation.new('4.3', 'mastodon/mastodon') end + config.before_configuration do + require 'mastodon/redis_config' + end + config.to_prepare do Doorkeeper::AuthorizationsController.layout 'modal' Doorkeeper::AuthorizedApplicationsController.layout 'admin' From 26e10aa203d18e452cdf836209875f05a6e01882 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 1 May 2024 01:39:28 +0200 Subject: [PATCH 055/658] Change width breakpoint for mobile placement behavior (#30131) --- app/javascript/styles/mastodon/components.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 9cb03bedf1..51596ec244 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -5616,7 +5616,7 @@ a.status-card { user-select: text; display: flex; - @media screen and (max-width: $no-gap-breakpoint) { + @media screen and (width <= 630px) { margin-top: auto; } } From a9dd68b90a8f8ae5bffb7ad97a34919bcf0f9d17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 10:00:43 +0200 Subject: [PATCH 056/658] Update dependency react-redux to v9.1.2 (#30146) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 5e83223a2a..f6e89bb266 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14456,24 +14456,21 @@ __metadata: linkType: hard "react-redux@npm:^9.0.4": - version: 9.1.1 - resolution: "react-redux@npm:9.1.1" + version: 9.1.2 + resolution: "react-redux@npm:9.1.2" dependencies: "@types/use-sync-external-store": "npm:^0.0.3" use-sync-external-store: "npm:^1.0.0" peerDependencies: "@types/react": ^18.2.25 react: ^18.0 - react-native: ">=0.69" redux: ^5.0.0 peerDependenciesMeta: "@types/react": optional: true - react-native: - optional: true redux: optional: true - checksum: 10c0/40ccdc8d48aefeed02c025f46e4a2e6641a2996fe985feb70d25feaaf8f101f6ef937cd1420909cad4c8869a8c79323ee071f5b090b011b950e5ae09100f5767 + checksum: 10c0/56ac98228e011b26e0202346af9c8dd408ad5ea8235d8761c8e05ea0953b8ca801cdf9d1f481fdec7b285d7f30ceef7238b46b3df7636ef77dd5c2ea8c5be5b2 languageName: node linkType: hard From 62992ba54a102a52ba49087f13c86a662f9d5807 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 10:14:45 +0200 Subject: [PATCH 057/658] Update dependency sass to v1.76.0 (#30138) 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 f6e89bb266..e45da3a480 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15309,15 +15309,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.75.0 - resolution: "sass@npm:1.75.0" + version: 1.76.0 + resolution: "sass@npm:1.76.0" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/1564ab2c8041c99a330cec93127fe8abcf65ac63eecb471610ed7f3126a2599a58b788a3a98eb8719f7f40b9b04e00c92bc9e11a9c2180ad582b8cba9fb030b0 + checksum: 10c0/976baf2c378e104f8d4ffca5375c8aa6f3d24f59d5c0a5db8d68a51f89edce45dedc25cfcd304b309fc8568d146de9e2c6cd189395e97bb2840d39feb13932ff languageName: node linkType: hard From 474e5ffaaeba42db6abacd0194720cdfc66f79f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 10:15:49 +0200 Subject: [PATCH 058/658] Update dependency dotenv to v3.1.1 (#30133) 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 d73de0320f..45815e6b44 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -220,7 +220,7 @@ GEM domain_name (0.6.20240107) doorkeeper (5.6.9) railties (>= 5) - dotenv (3.1.0) + dotenv (3.1.1) drb (2.2.1) ed25519 (1.3.0) elasticsearch (7.13.3) From ac1d830e6cd795b7658d0ae7fe7cec52cd24cf6e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 10:27:47 +0200 Subject: [PATCH 059/658] Update dependency aws-sdk-s3 to v1.149.0 (#30136) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 45815e6b44..ad94d00476 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -102,8 +102,8 @@ GEM attr_required (1.0.2) awrence (1.2.1) aws-eventstream (1.3.0) - aws-partitions (1.920.0) - aws-sdk-core (3.193.0) + aws-partitions (1.922.0) + aws-sdk-core (3.194.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) @@ -111,8 +111,8 @@ GEM aws-sdk-kms (1.80.0) aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.148.0) - aws-sdk-core (~> 3, >= 3.193.0) + aws-sdk-s3 (1.149.0) + aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) From d97d31cce664281d868e4c661451687a301c97c8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 10:28:13 +0200 Subject: [PATCH 060/658] Update dependency irb to v1.13.0 (#30143) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ad94d00476..3394930e0d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -350,8 +350,8 @@ GEM activesupport (>= 3.0) nokogiri (>= 1.6) io-console (0.7.2) - irb (1.12.0) - rdoc + irb (1.13.0) + rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) json (2.7.2) @@ -605,7 +605,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.9.0) - reline (0.5.2) + reline (0.5.4) io-console (~> 0.5) request_store (1.6.0) rack (>= 1.4) From 2447497a4cc6ea305f9431e4d8002b7abb750c7e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 2 May 2024 04:31:06 -0400 Subject: [PATCH 061/658] Status length validation spec updates (#30132) --- .../status_length_validator_spec.rb | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/spec/validators/status_length_validator_spec.rb b/spec/validators/status_length_validator_spec.rb index 06625917bd..ead69dfe21 100644 --- a/spec/validators/status_length_validator_spec.rb +++ b/spec/validators/status_length_validator_spec.rb @@ -4,6 +4,8 @@ require 'rails_helper' describe StatusLengthValidator do describe '#validate' do + before { stub_const("#{described_class}::MAX_CHARS", 500) } # Example values below are relative to this baseline + it 'does not add errors onto remote statuses' do status = instance_double(Status, local?: false) allow(status).to receive(:errors) @@ -22,27 +24,27 @@ describe StatusLengthValidator do expect(status).to_not have_received(:errors) end - it 'adds an error when content warning is over 500 characters' do - status = instance_double(Status, spoiler_text: 'a' * 520, text: '', errors: activemodel_errors, local?: true, reblog?: false) + it 'adds an error when content warning is over character limit' do + status = status_double(spoiler_text: 'a' * 520) subject.validate(status) expect(status.errors).to have_received(:add) end - it 'adds an error when text is over 500 characters' do - status = instance_double(Status, spoiler_text: '', text: 'a' * 520, errors: activemodel_errors, local?: true, reblog?: false) + it 'adds an error when text is over character limit' do + status = status_double(text: 'a' * 520) subject.validate(status) expect(status.errors).to have_received(:add) end - it 'adds an error when text and content warning are over 500 characters total' do - status = instance_double(Status, spoiler_text: 'a' * 250, text: 'b' * 251, errors: activemodel_errors, local?: true, reblog?: false) + it 'adds an error when text and content warning are over character limit total' do + status = status_double(spoiler_text: 'a' * 250, text: 'b' * 251) subject.validate(status) expect(status.errors).to have_received(:add) end it 'counts URLs as 23 characters flat' do text = ('a' * 476) + " http://#{'b' * 30}.com/example" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + status = status_double(text: text) subject.validate(status) expect(status.errors).to_not have_received(:add) @@ -50,7 +52,7 @@ describe StatusLengthValidator do it 'does not count non-autolinkable URLs as 23 characters flat' do text = ('a' * 476) + "http://#{'b' * 30}.com/example" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + status = status_double(text: text) subject.validate(status) expect(status.errors).to have_received(:add) @@ -58,14 +60,14 @@ describe StatusLengthValidator do it 'does not count overly long URLs as 23 characters flat' do text = "http://example.com/valid?#{'#foo?' * 1000}" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + status = status_double(text: text) subject.validate(status) expect(status.errors).to have_received(:add) end it 'counts only the front part of remote usernames' do text = ('a' * 475) + " @alice@#{'b' * 30}.com" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + status = status_double(text: text) subject.validate(status) expect(status.errors).to_not have_received(:add) @@ -73,7 +75,7 @@ describe StatusLengthValidator do it 'does count both parts of remote usernames for overly long domains' do text = "@alice@#{'b' * 500}.com" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) + status = status_double(text: text) subject.validate(status) expect(status.errors).to have_received(:add) @@ -82,6 +84,17 @@ describe StatusLengthValidator do private + def status_double(spoiler_text: '', text: '') + instance_double( + Status, + spoiler_text: spoiler_text, + text: text, + errors: activemodel_errors, + local?: true, + reblog?: false + ) + end + def activemodel_errors instance_double(ActiveModel::Errors, add: nil) end From 309f352e6a2fe68729ef5b723c986bc536fe0773 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 10:57:30 +0200 Subject: [PATCH 062/658] New Crowdin Translations (automated) (#30140) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ia.json | 12 +++ app/javascript/mastodon/locales/pt-BR.json | 13 +++ app/javascript/mastodon/locales/sk.json | 2 + app/javascript/mastodon/locales/sr-Latn.json | 13 +++ app/javascript/mastodon/locales/sr.json | 13 +++ config/locales/devise.ia.yml | 1 + config/locales/doorkeeper.fy.yml | 1 + config/locales/doorkeeper.sr-Latn.yml | 1 + config/locales/doorkeeper.sr.yml | 1 + config/locales/fy.yml | 34 ++++++++ config/locales/ia.yml | 92 ++++++++++++++++++++ config/locales/simple_form.fy.yml | 4 + config/locales/simple_form.ia.yml | 57 ++++++++++++ config/locales/simple_form.pt-BR.yml | 1 + config/locales/simple_form.sr-Latn.yml | 4 + config/locales/simple_form.sr.yml | 4 + config/locales/sk.yml | 79 +++++++++++++++++ config/locales/sr-Latn.yml | 1 + config/locales/sr.yml | 1 + 19 files changed, 334 insertions(+) diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 1b969639dc..d30038d9cc 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Benque tu conto non es serrate, le personal de {domain} pensa que es un bon idea que tu revide manualmente le sequente requestas de iste contos.", "follow_suggestions.curated_suggestion": "Selection del equipa", "follow_suggestions.dismiss": "Non monstrar novemente", + "follow_suggestions.featured_longer": "Seligite con cura per le equipa de {domain}", + "follow_suggestions.friends_of_friends_longer": "Popular inter le gente que tu seque", "follow_suggestions.hints.featured": "Iste profilo ha essite seligite manualmente per le equipa de {domain}.", "follow_suggestions.hints.friends_of_friends": "Iste profilo es popular inter le gente que tu seque.", "follow_suggestions.hints.most_followed": "Iste profilo es un del plus sequites sur {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Iste profilo es similar al profilos que tu ha recentemente sequite.", "follow_suggestions.personalized_suggestion": "Suggestion personalisate", "follow_suggestions.popular_suggestion": "Suggestion personalisate", + "follow_suggestions.popular_suggestion_longer": "Popular sur {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similar al profilos que tu ha sequite recentemente", "follow_suggestions.view_all": "Vider toto", "follow_suggestions.who_to_follow": "Qui sequer", "followed_tags": "Hashtags sequite", @@ -470,6 +474,14 @@ "notification.follow_request": "{name} ha requestate de sequer te", "notification.mention": "{name} te ha mentionate", "notification.moderation-warning.learn_more": "Apprender plus", + "notification.moderation_warning": "Tu ha recipite un advertimento de moderation", + "notification.moderation_warning.action_delete_statuses": "Alcunes de tu messages ha essite removite.", + "notification.moderation_warning.action_disable": "Tu conto ha essite disactivate.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Alcunes de tu messages ha essite marcate como sensibile.", + "notification.moderation_warning.action_none": "Tu conto ha recipite un advertimento de moderation.", + "notification.moderation_warning.action_sensitive": "Tu messages essera marcate como sensibile a partir de ora.", + "notification.moderation_warning.action_silence": "Tu conto ha essite limitate.", + "notification.moderation_warning.action_suspend": "Tu conto ha essite suspendite.", "notification.own_poll": "Tu sondage ha finite", "notification.poll": "Un sondage in le qual tu ha votate ha finite", "notification.reblog": "{name} ha impulsate tu message", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 6bda11058f..b11daeaaa7 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Apesar de seu perfil não ser trancado, {domain} exige que você revise a solicitação para te seguir destes perfis manualmente.", "follow_suggestions.curated_suggestion": "Escolha da equipe", "follow_suggestions.dismiss": "Não mostrar novamente", + "follow_suggestions.featured_longer": "Escolhido à mão pela equipe de {domain}", + "follow_suggestions.friends_of_friends_longer": "Popular entre as pessoas que você segue", "follow_suggestions.hints.featured": "Este perfil foi escolhido a dedo pela equipe {domain}.", "follow_suggestions.hints.friends_of_friends": "Este perfil é popular entre as pessoas que você segue.", "follow_suggestions.hints.most_followed": "Este perfil é um dos mais seguidos em {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Este perfil é semelhante aos perfis que você seguiu recentemente.", "follow_suggestions.personalized_suggestion": "Sugestão personalizada", "follow_suggestions.popular_suggestion": "Sugestão popular", + "follow_suggestions.popular_suggestion_longer": "Popular em {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similar a perfis que você seguiu recentemente", "follow_suggestions.view_all": "Visualizar tudo", "follow_suggestions.who_to_follow": "Quem seguir", "followed_tags": "Hashtags seguidas", @@ -469,6 +473,15 @@ "notification.follow": "{name} te seguiu", "notification.follow_request": "{name} quer te seguir", "notification.mention": "{name} te mencionou", + "notification.moderation-warning.learn_more": "Aprender mais", + "notification.moderation_warning": "Você recebeu um aviso de moderação", + "notification.moderation_warning.action_delete_statuses": "Algumas das suas publicações foram removidas.", + "notification.moderation_warning.action_disable": "Sua conta foi desativada.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algumas de suas publicações foram marcadas por ter conteúdo sensível.", + "notification.moderation_warning.action_none": "Sua conta recebeu um aviso de moderação.", + "notification.moderation_warning.action_sensitive": "Suas publicações serão marcadas como sensíveis a partir de agora.", + "notification.moderation_warning.action_silence": "Sua conta foi limitada.", + "notification.moderation_warning.action_suspend": "Sua conta foi suspensa.", "notification.own_poll": "Sua enquete terminou", "notification.poll": "Uma enquete que você votou terminou", "notification.reblog": "{name} deu boost no teu toot", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index e126fdef02..2863442415 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -448,6 +448,7 @@ "notification.own_poll": "Vaša anketa sa skončila", "notification.poll": "Anketa, v ktorej ste hlasovali, sa skončila", "notification.reblog": "{name} zdieľa váš príspevok", + "notification.relationships_severance_event": "Stratené prepojenia s {name}", "notification.relationships_severance_event.learn_more": "Zisti viac", "notification.status": "{name} uverejňuje niečo nové", "notification.update": "{name} upravuje príspevok", @@ -490,6 +491,7 @@ "notifications.policy.filter_new_accounts_title": "Nové účty", "notifications.policy.filter_not_followers_title": "Ľudia, ktorí ťa nenasledujú", "notifications.policy.filter_not_following_title": "Ľudia, ktorých nenasleduješ", + "notifications.policy.filter_private_mentions_title": "Nevyžiadané priame spomenutia", "notifications.policy.title": "Filtrovať oznámenia od…", "notifications_permission_banner.enable": "Povoliť upozornenia na ploche", "notifications_permission_banner.how_to_control": "Ak chcete dostávať upozornenia, keď Mastodon nie je otvorený, povoľte upozornenia na ploche. Po ich zapnutí môžete presne kontrolovať, ktoré typy interakcií generujú upozornenia na ploche, a to prostredníctvom tlačidla {icon} vyššie.", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 3eea87d5ec..67b706fa13 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Iako vaš nalog nije zaključan, osoblje {domain} smatra da biste možda želeli da ručno pregledate zahteve za praćenje sa ovih naloga.", "follow_suggestions.curated_suggestion": "Izbor osoblja", "follow_suggestions.dismiss": "Ne prikazuj ponovo", + "follow_suggestions.featured_longer": "Ručno odabrao tim {domain}", + "follow_suggestions.friends_of_friends_longer": "Popularno među ljudima koje pratite", "follow_suggestions.hints.featured": "Ovaj profil je ručno izabrao tim {domain}.", "follow_suggestions.hints.friends_of_friends": "Ovaj profil je popularan među ljudima koje pratite.", "follow_suggestions.hints.most_followed": "Ovaj profil je jedan od najpraćenijih na {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Ovaj profil je sličan profilima koje ste nedavno zapratili.", "follow_suggestions.personalized_suggestion": "Personalizovani predlog", "follow_suggestions.popular_suggestion": "Popularni predlog", + "follow_suggestions.popular_suggestion_longer": "Popularno na {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Slično profilima koje ste nedavno zapratili", "follow_suggestions.view_all": "Prikaži sve", "follow_suggestions.who_to_follow": "Koga pratiti", "followed_tags": "Praćene heš oznake", @@ -469,6 +473,15 @@ "notification.follow": "{name} vas je zapratio", "notification.follow_request": "{name} je zatražio da vas prati", "notification.mention": "{name} vas je pomenuo", + "notification.moderation-warning.learn_more": "Saznajte više", + "notification.moderation_warning": "Dobili ste moderatorsko upozorenje", + "notification.moderation_warning.action_delete_statuses": "Neke od vaših objava su uklonjene.", + "notification.moderation_warning.action_disable": "Vaš nalog je onemogućen.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Neke od vaših objava su obeležene kao osetljive.", + "notification.moderation_warning.action_none": "Vaš nalog je dobio moderatorsko upozorenje.", + "notification.moderation_warning.action_sensitive": "Vaše objave će ubuduće biti označene kao osetljive.", + "notification.moderation_warning.action_silence": "Vaš nalog je ograničen.", + "notification.moderation_warning.action_suspend": "Vaš nalog je suspendovan.", "notification.own_poll": "Vaša anketa je završena", "notification.poll": "Završena je anketa u kojoj ste glasali", "notification.reblog": "{name} je podržao vašu objavu", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 69f755a0b6..9898a10a3e 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Иако ваш налог није закључан, особље {domain} сматра да бисте можда желели да ручно прегледате захтеве за праћење са ових налога.", "follow_suggestions.curated_suggestion": "Избор особља", "follow_suggestions.dismiss": "Не приказуј поново", + "follow_suggestions.featured_longer": "Ручно одабрао тим {domain}", + "follow_suggestions.friends_of_friends_longer": "Популарно међу људима које пратите", "follow_suggestions.hints.featured": "Овај профил је ручно изабрао тим {domain}.", "follow_suggestions.hints.friends_of_friends": "Овај профил је популаран међу људима које пратите.", "follow_suggestions.hints.most_followed": "Овај профил је један од најпраћенијих на {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Овај профил је сличан профилима које сте недавно запратили.", "follow_suggestions.personalized_suggestion": "Персонализовани предлог", "follow_suggestions.popular_suggestion": "Популарни предлог", + "follow_suggestions.popular_suggestion_longer": "Популарно на {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Слично профилима које сте недавно запратили", "follow_suggestions.view_all": "Прикажи све", "follow_suggestions.who_to_follow": "Кога пратити", "followed_tags": "Праћене хеш ознаке", @@ -469,6 +473,15 @@ "notification.follow": "{name} вас је запратио", "notification.follow_request": "{name} је затражио да вас прати", "notification.mention": "{name} вас је поменуо", + "notification.moderation-warning.learn_more": "Сазнајте више", + "notification.moderation_warning": "Добили сте модераторско упозорење", + "notification.moderation_warning.action_delete_statuses": "Неке од ваших објава су уклоњене.", + "notification.moderation_warning.action_disable": "Ваш налог је онемогућен.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Неке од ваших објава су обележене као осетљиве.", + "notification.moderation_warning.action_none": "Ваш налог је добио модераторско упозорење.", + "notification.moderation_warning.action_sensitive": "Ваше објаве ће убудуће бити означене као осетљиве.", + "notification.moderation_warning.action_silence": "Ваш налог је ограничен.", + "notification.moderation_warning.action_suspend": "Ваш налог је суспендован.", "notification.own_poll": "Ваша анкета је завршена", "notification.poll": "Завршена је анкета у којој сте гласали", "notification.reblog": "{name} је подржао вашу објаву", diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index d180a46a6f..6c89f4c6d4 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -16,6 +16,7 @@ ia: pending: Tu conto es ancora sub revision. timeout: Tu session ha expirate. Per favor reaperi session pro continuar. unauthenticated: Es necessari aperir session o crear un conto ante de continuar. + unconfirmed: Es necessari confirmar tu adresse de e-mail ante de continuar. mailer: confirmation_instructions: action: Verificar adresse de e-mail diff --git a/config/locales/doorkeeper.fy.yml b/config/locales/doorkeeper.fy.yml index a43defc427..51f0055ff6 100644 --- a/config/locales/doorkeeper.fy.yml +++ b/config/locales/doorkeeper.fy.yml @@ -174,6 +174,7 @@ fy: read:filters: jo filters besjen read:follows: de accounts dy’tsto folgest besjen read:lists: jo listen besjen + read:me: allinnich de basisgegevens fan jo account lêze read:mutes: jo negearre brûkers besjen read:notifications: jo meldingen besjen read:reports: jo rapportearre berjochten besjen diff --git a/config/locales/doorkeeper.sr-Latn.yml b/config/locales/doorkeeper.sr-Latn.yml index a4eb7bd33e..58ed5e8b68 100644 --- a/config/locales/doorkeeper.sr-Latn.yml +++ b/config/locales/doorkeeper.sr-Latn.yml @@ -174,6 +174,7 @@ sr-Latn: read:filters: pogledaj svoje filtere read:follows: pogledaj koga pratiš read:lists: pogledaj svoje liste + read:me: čita samo osnovne informacije o vašem nalogu read:mutes: pogledaj ignorisanja read:notifications: pogledaj svoja obaveštenja read:reports: pogledaj svoje prijave diff --git a/config/locales/doorkeeper.sr.yml b/config/locales/doorkeeper.sr.yml index 010eb23eb5..f40a05e90d 100644 --- a/config/locales/doorkeeper.sr.yml +++ b/config/locales/doorkeeper.sr.yml @@ -174,6 +174,7 @@ sr: read:filters: погледај своје филтере read:follows: погледај кога пратиш read:lists: погледај своје листе + read:me: чита само основне информације о вашем налогу read:mutes: погледај игнорисања read:notifications: погледај своја обавештења read:reports: погледај своје пријаве diff --git a/config/locales/fy.yml b/config/locales/fy.yml index 1d62f7c6af..1f1a27fec4 100644 --- a/config/locales/fy.yml +++ b/config/locales/fy.yml @@ -597,6 +597,9 @@ fy: actions_description_html: Beslis hokker maatregel nommen wurde moat om dizze rapportaazje op te lossen. Wannear’t jo in (straf)maatregel tsjin it rapportearre account nimme, kriget de account in e-mailmelding, behalve wannear’t de spam-kategory keazen is. actions_description_remote_html: Beslút hokker aksje nommen wurde moat om dizze rapportaazje ôf te hanneljen. Dit hat allinnich ynfloed op hoe’t jo server kommunisearret mei dizze eksterne account en omgiet mei de ynhâld. add_to_report: Mear oan de rapportaazje tafoegje + already_suspended_badges: + local: Al opskoarte op dizze server + remote: Al opskoarte op harren server are_you_sure: Binne jo wis? assign_to_self: Oan my tawize assigned: Tawizen moderator @@ -748,6 +751,7 @@ fy: desc_html: Dit is ôfhinklik fan eksterne scripts fan hCaptcha, wat feilichheids- en privacyrisiko’s meibringe kin. Boppe dat kin dit it registraasjeproses bot minder tagonklik meitsje foar guon (foaral handicapte) minsken. Om dizze redenen kinne jo it beste alternative maatregels oerweagje, lykas registraasje op basis fan goedkarring of op útnûging. title: Nije brûkers moatte in CAPTCHA oplosse om harren account te befêstigjen content_retention: + danger_zone: Gefaresône preamble: Tafersjoch hâlde op hoe’t berjochten en media fan brûkers op Mastodon bewarre wurde. title: Bewartermyn berjochten default_noindex: @@ -767,6 +771,7 @@ fy: disabled: Oan net ien users: Oan oanmelde lokale brûkers registrations: + moderation_recommandation: Soargje derfoar dat jo in adekwaat en responsyf moderaasjeteam hawwe eardat jo registraasjes foar elkenien iepenstelle! preamble: Tafersjoch hâlde op wa’t in account op dizze server registrearje kin. title: Registraasjes registrations_mode: @@ -1647,13 +1652,24 @@ fy: import: Ymportearje import_and_export: Ymportearje en eksportearje migrate: Accountmigraasje + notifications: E-mailmeldingen preferences: Ynstellingen profile: Profyl relationships: Folgers en folgjenden + severed_relationships: Ferbrutsen folchrelaasjes statuses_cleanup: Automatysk berjochten fuortsmite strikes: Fêststelde skeiningen two_factor_authentication: Twa-stapsferifikaasje webauthn_authentication: Befeiligingskaaien + severed_relationships: + download: Downloade (%{count}) + event_type: + account_suspension: Accountopskoarting (%{target_name}) + domain_block: Serveropskoarting (%{target_name}) + user_domain_block: Jo hawwe %{target_name} blokkearre + lost_followers: Ferlerne folgers + lost_follows: Ferlerne folge accounts + type: Barren statuses: attached: audio: @@ -1747,6 +1763,7 @@ fy: contrast: Mastodon (heech kontrast) default: Mastodon (donker) mastodon-light: Mastodon (ljocht) + system: Automatysk (systeemtema brûke) time: formats: default: "%d %B %Y om %H:%M" @@ -1838,13 +1855,30 @@ fy: apps_ios_action: Fia de App Store downloade apps_step: Us offisjele apps downloade apps_title: Mastodon-apps + checklist_subtitle: 'Litte wy oan dit nije sosjale aventoer begjinne:' + checklist_title: Wolkomstkontrôlelist edit_profile_action: Personalisearje + edit_profile_step: Wannear’t jo mear oer josels fertelle, krije jo mear ynteraksje mei oare minsken. edit_profile_title: Jo profyl personalisearje explanation: Hjir binne inkelde tips om jo op wei te helpen feature_action: Mear ynfo + feature_audience: Mastodon biedt jo in unike mooglikheid om jo publyk te behearen sûnder tuskenpersoanen. Mastodon, ymplemintearre yn jo eigen ynfrastruktuer, stelt jo yn steat om elke oare Mastodon-server online te folgjen en troch harren folge te wurden, en stiet ûnder kontrôle fan net ien, útsein dy fan jo. + feature_audience_title: Bou jo publyk yn fertrouwen op + feature_control: Jo witte sels it bêste wat jo op jo tiidline sjen wolle. Gjin algoritmen of advertinsjes om jo tiid te fergriemen. Folgje elkenien op elke Mastodon-server fan ien account ôf en ûntfang harren berjochten yn gronologyske folchoarder, en meitsje jo hoekje op it ynternet in bytsje mear as josels. + feature_control_title: Hâld kontrôle oer jo eigen tiidline + feature_creativity: Mastodon stipet audio-, fideo- en fotoberjochten, tagonklikheidsbeskriuwingen, enkêten, ynhâldswarskôgingen, animearre avatars, oanpaste emoji, kontrôle oer it bywurkjen fan miniatueren en mear, om jo te helpen josels online te uterjen. Oft jo no jo keunst, muzyk of podcast publisearje, Mastodon stiet foar jo klear. + feature_creativity_title: Bjusterbaarlike kreativiteit + feature_moderation: Mastodon leit de beslútfoarming wer yn jo hannen. Elke server makket harren eigen rigels en foarskriften, dy’t lokaal hanthavene wurde en net fan boppe ôf, lykas sosjale media fan bedriuwen, wêrtroch it it meast fleksibel is yn it reagearjen op de behoeften fan ferskate groepen minsken. Wurd lid fan in server mei de rigels wêrmei’t jo akkoard geane, of host jo eigen. + feature_moderation_title: Moderaasje sa as it heart follow_action: Folgje + follow_step: Op Mastodon draait it hielendal om it folgjen fan ynteressante minsken. + follow_title: Personalisearje jo starttiidline + follows_subtitle: Folgje bekende accounts follows_title: Wa te folgjen follows_view_more: Mear minsken om te folgjen besjen + hashtags_recent_count: + one: "%{people} persoan yn de ôfrûne 2 dagen" + other: "%{people} persoanen yn de ôfrûne 2 dagen" hashtags_subtitle: Wat der yn de ôfrûne 2 dagen bard is ferkenne hashtags_title: Populêre hashtags hashtags_view_more: Mear populêre hashtags besjen diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 9ec64b1390..ff7b47c1fe 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -111,12 +111,23 @@ ia: public: Public push_subscription_expires: Subscription PuSH expira le redownload: Actualisar profilo + redownloaded_msg: Le profilo de %{username} ha essite actualisate desde le origine + reject: Rejectar + rejected_msg: Le demanda de inscription de %{username} ha essite rejectate + remote_suspension_irreversible: Le datos de iste conto ha essite irreversibilemente delite. + remote_suspension_reversible_hint_html: Le conto ha essite suspendite sur su servitor, e le datos essera removite completemente le %{date}. Usque alora, le servitor remote pote restaurar iste conto sin effectos negative. Si tu vole remover immediatemente tote le datos del conto, tu pote facer lo hic infra. + remove_avatar: Remover avatar + remove_header: Remover capite + removed_avatar_msg: Le imagine de avatar de %{username} ha essite removite + removed_header_msg: Le imagine de capite de %{username} ha essite removite resend_confirmation: already_confirmed: Iste usator jam es confirmate send: Reinviar ligamine de confirmation success: Ligamine de confirmation inviate con successo! reset: Reinitialisar reset_password: Reinitialisar contrasigno + resubscribe: Resubscriber + role: Rolo search: Cercar search_same_email_domain: Altere usatores con le mesme dominio de e-mail search_same_ip: Altere usatores con le mesme IP @@ -124,22 +135,34 @@ ia: security_measures: only_password: Solmente contrasigno password_and_2fa: Contrasigno e 2FA + sensitive: Fortiar sensibile + sensitized: Marcate como sensibile + shared_inbox_url: URL del cassa de entrata condividite show: created_reports: Reportos facite targeted_reports: Signalate per alteres + silence: Limitar silenced: Limitate statuses: Messages + strikes: Previe admonitiones subscribe: Subscriber suspend: Suspender suspended: Suspendite + suspension_irreversible: Le datos de iste conto ha essite irreversibilemente delite. Tu pote disfacer le suspension de iste conto pro render lo usabile, ma isto non recuperara alcun datos precedente. + suspension_reversible_hint_html: Le conto ha essite suspendite, e le datos essera removite completemente le %{date}. Usque alora, le conto pote esser restaurate sin effectos negative. Si tu vole remover immediatemente tote le datos del conto, tu pote facer lo hic infra. title: Contos unblock_email: Disblocar adresse de e-mail unblocked_email_msg: Adresse de e-mail de %{username} disblocate con successo unconfirmed_email: E-mail non confirmate + undo_sensitized: Non plus fortiar sensibile undo_silenced: Disfacer le limite undo_suspension: Disfacer le suspension + unsilenced_msg: Le limite del conto de %{username} ha essite cancellate + unsubscribe: Desubscriber username: Nomine de usator view_domain: Vider summario de dominio + warn: Avisar + web: Web action_logs: action_types: change_email_user: Cambiar e-mail pro le usator @@ -148,6 +171,7 @@ ia: create_account_warning: Crear un advertimento create_announcement: Crear annuncio create_ip_block: Crear un regula IP + create_user_role: Crear un rolo destroy_announcement: Deler annuncio destroy_ip_block: Deler le regula IP destroy_status: Deler le message @@ -167,6 +191,7 @@ ia: update_custom_emoji: Actualisar emoji personalisate update_ip_block: Actualisar le regula IP update_status: Actualisar le message + update_user_role: Actualisar rolo actions: change_email_user_html: "%{name} cambiava le adresse de e-mail address del usator %{target}" create_announcement_html: "%{name} creava un nove annuncio %{target}" @@ -205,6 +230,7 @@ ia: media_storage: Immagazinage de medios new_users: nove usatores opened_reports: reportos aperte + software: Software top_languages: Linguas le plus active top_servers: Servitores le plus active website: Sito web @@ -220,6 +246,10 @@ ia: edit: Modificar un bloco de dominio export: Exportar import: Importar + new: + severity: + silence: Limitar + suspend: Suspender private_comment: Commento private public_comment: Commento public email_domain_blocks: @@ -239,9 +269,16 @@ ia: status: Stato title: Sequer le recommendationes instances: + back_to_all: Toto + back_to_limited: Limitate back_to_warning: Advertimento by_domain: Dominio content_policies: + comment: Nota interne + policies: + silence: Limitar + suspend: Suspender + policy: Politica reason: Ration public dashboard: instance_accounts_dimension: Contos le plus sequite @@ -249,14 +286,23 @@ ia: delivery: unavailable: Non disponibile empty: Necun dominios trovate. + moderation: + all: Toto + limited: Limitate + title: Moderation private_comment: Commento private public_comment: Commento public + title: Federation total_blocked_by_us: Blocate per nos total_followed_by_us: Sequite per nos invites: deactivate_all: Disactivar toto filter: + all: Toto available: Disponibile + expired: Expirate + title: Filtro + title: Invitationes ip_blocks: add_new: Crear regula delete: Deler @@ -264,15 +310,19 @@ ia: '1209600': 2 septimanas '15778476': 6 menses '2629746': 1 mense + '31556952': 1 anno '86400': 1 die + '94670856': 3 annos new: title: Crear un nove regula IP title: Regulas IP relays: delete: Deler + description_html: Un repetitor de federation es un servitor intermediari que excambia grande volumines de messages public inter le servitores que se inscribe e publica a illo. Illo pote adjutar le servitores micre e medie a discoperir le contento del fediverso, sin requirer que le usatores local seque manualmente altere personas sur servitores distante. disable: Disactivar disabled: Disactivate enable: Activar + enable_hint: Un vice activate, tu servitor se inscribera a tote le messages public de iste repetitor, e comenciara a inviar le messages public de iste servitor a illo. enabled: Activate save_and_enable: Salveguardar e activar status: Stato @@ -283,9 +333,11 @@ ia: category: Categoria confirm: Confirmar delete_and_resolve: Deler le messages + no_one_assigned: Nemo notes: create: Adder un nota delete: Deler + title: Notas skip_to_actions: Saltar al actiones status: Stato updated_at: Actualisate @@ -294,6 +346,11 @@ ia: assigned_users: one: "%{count} usator" other: "%{count} usatores" + categories: + invites: Invitationes + moderation: Moderation + special: Special + delete: Deler everyone: Permissiones predefinite privileges: delete_user_data: Deler le datos de usator @@ -302,6 +359,7 @@ ia: manage_rules: Gerer le regulas manage_settings: Gerer le parametros manage_users: Gerer usatores + title: Rolos rules: delete: Deler settings: @@ -317,8 +375,25 @@ ia: title: Parametros de servitor site_uploads: delete: Deler file incargate + software_updates: + documentation_link: Pro saper plus + title: Actualisationes disponibile + type: Typo + types: + major: Version major + minor: Version minor + version: Version statuses: + account: Autor + application: Application + batch: + report: Reporto + deleted: Delite + favourites: Favoritos + history: Chronologia del versiones language: Lingua + media: + title: Medios metadata: Metadatos open: Aperir message original_status: Message original @@ -337,6 +412,8 @@ ia: action: Vider le actualisationes disponibile upload_check_privacy_error: action: Verifica hic pro plus de information + application_mailer: + unsubscribe: Desubscriber edit_profile: other: Alteres existing_username_validator: @@ -397,6 +474,21 @@ ia: login_activities: authentication_methods: password: contrasigno + mail_subscriptions: + unsubscribe: + action: Si, desubscriber + complete: Desubscribite + confirmation_html: Es tu secur de voler cancellar le subscription al %{type} de Mastodon sur %{domain} pro tu adresse de e-mail %{email}? Tu pote sempre resubscriber te a partir del parametros de notification in e-mail. + emails: + notification_emails: + favourite: notificationes de favorites in e-mail + follow: notificationes de sequimento in e-mail + follow_request: requestas de sequimento in e-mail + mention: notificationes de mentiones in e-mail + reblog: notificationes de impulsos in e-mail + resubscribe_html: Si tu ha cancellate le subscription in error, tu pote resubscriber te a partir del parametros de notification in e-mail. + success_html: Tu non recipera plus %{type} pro Mastodon sur %{domain} a tu adresse de e-mail %{email}. + title: Desubcriber migrations: errors: not_found: non poterea esser trovate diff --git a/config/locales/simple_form.fy.yml b/config/locales/simple_form.fy.yml index fa1633c901..8d599324b3 100644 --- a/config/locales/simple_form.fy.yml +++ b/config/locales/simple_form.fy.yml @@ -77,10 +77,13 @@ fy: warn: Ferstopje de filtere ynhâld efter in warskôging, mei de titel fan it filter as warskôgingstekst form_admin_settings: activity_api_enabled: Tal lokaal publisearre artikelen, aktive brûkers en nije registraasjes yn wyklikse werjefte + backups_retention_period: Brûkers hawwe de mooglikheid om argiven fan harren berjochten te generearjen om letter te downloaden. Wannear ynsteld op in positive wearde, wurde dizze argiven automatysk fuortsmiten út jo ûnthâld nei it opjûne oantal dagen. bootstrap_timeline_accounts: Dizze accounts wurde boppe oan de oanrekommandaasjes oan nije brûkers toand. Meardere brûkersnammen troch komma’s skiede. closed_registrations_message: Werjûn wannear’t registraasje fan nije accounts útskeakele is + content_cache_retention_period: Alle berjochten fan oare servers (ynklusyf boosts en reaksjes) wurde fuortsmiten nei it opjûne oantal dagen, nettsjinsteande iennige lokale brûkersynteraksje mei dy berjochten. Dit oanbelanget ek berjochten dy’t in lokale brûker oan harren blêdwizers tafoege hat of as favoryt markearre hat. Priveeberjochten tusken brûkers fan ferskate servers gean ek ferlern en binne ûnmooglik te werstellen. It gebrûk fan dizze ynstelling is bedoeld foar servers dy’t in spesjaal doel tsjinje en oertrêdet in protte brûkersferwachtingen wannear’t dizze foar algemien gebrûk ymplemintearre wurdt. custom_css: Jo kinne oanpaste CSS tapasse op de webferzje fan dizze Mastodon-server. mascot: Oerskriuwt de yllustraasje yn de avansearre webomjouwing. + media_cache_retention_period: Mediabestannen fan berjochten fan eksterne brûkers wurde op jo server yn de buffer bewarre. Wannear ynsteld op in positive wearde, wurde media fuortsmiten nei it opjûne oantal dagen. As de mediagegevens opfrege wurde neidat se fuortsmiten binne, wurde se opnij download wannear de orizjinele ynhâld noch hieltyd beskikber is. Fanwegen beheiningen op hoe faak keppelingsfoarbylden websites fan tredden rieplachtsje, wurdt oanrekommandearre om dizze wearde yn te stellen op op syn minste 14 dagen. Oars wurde keppelingsfoarbylden net op oanfraach bywurke. peers_api_enabled: In list mei domeinnammen, dêr’t dizze server yn fediverse kontakt hân mei hat. Hjir wurdt gjin data dield, oft jo mei in bepaalde server federearrest, mar alinnich, dat jo server dat wit. Dit wurdt foar tsjinsten brûkt, dy’t statistiken oer federaasje yn algemiene sin sammelet. profile_directory: De brûkersgids befettet in list fan alle brûkers dy¥t derfoar keazen hawwe om ûntdekt wurde te kinnen. require_invite_text: Meitsje it ynfoljen fan ‘Wêrom wolle jo jo hjir registrearje?’ ferplicht yn stee fan opsjoneel, wannear’t registraasjes hânmjittich goedkard wurde moatte @@ -240,6 +243,7 @@ fy: backups_retention_period: Bewartermyn brûkersargyf bootstrap_timeline_accounts: Accounts dy’t altyd oan nije brûkers oanrekommandearre wurde closed_registrations_message: Oanpast berjocht wannear registraasje útskeakele is + content_cache_retention_period: Bewartermyn foar eksterne ynhâld custom_css: Oanpaste CSS mascot: Oanpaste maskotte (legacy) media_cache_retention_period: Bewartermyn mediabuffer diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index 5e9dda2a13..05a5fa5013 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -3,12 +3,58 @@ ia: simple_form: hints: account: + discoverable: Tu messages public e tu profilo pote esser consiliate o recommendate in varie areas de Mastodon e tu profilo pote esser suggerite a altere usatores. + display_name: Tu prenomine e nomine de familia o tu pseudonymo. + fields: Tu pagina principal, pronomines, etate, toto lo que tu vole. + indexable: Tu messages public pote apparer in resultatos del recerca sur Mastodon. Illes qui ha interagite con tu messages totevia pote cercar les. note: 'Tu pote @mentionar altere personas o #hashtags.' + show_collections: Le personas potera navigar per tu sequites e sequaces. Le personas potera navigar per tu sequites e sequaces. + unlocked: Le personas potera sequer te sin requestar approbation. Dismarca si tu desira revider le requestas de sequer e selige si acceptar o rejectar nove sequaces. + account_alias: + acct: Specifica le nomine_de_usator@dominio del conto ab que tu vole mover + account_migration: + acct: Specifica le nomine_de_usator@dominio del conto a que tu vole mover + account_warning_preset: + text: Tu pote usar le syntaxe de message, tal como URLs, hashtags e mentiones + title: Optional. Non visibile al destinatario + admin_account_action: + include_statuses: Le usator videra que messages ha causate le action o aviso de moderation + send_email_notification: Le usator recipera un explication de cosa eveniva con lor conto + text_html: Optional. Tu pote usar le syntaxe de message. Tu pote adder avisos preconfigurate pro sparniar tempore + type_html: Selige lo que tu vole facer con %{acct} + types: + disable: Impedir al usator de usar lor conto, sin deler o celar lor contentos. + none: Usar lo pro inviar un aviso al usator, sin discatenar ulle altere action. + sensitive: Fortiar tote le annexos multimedial de iste usator a esser signalate como sensibile. + silence: Impedir al usator de poter publicar messages con public visibilitate, celar lor messages e notificationes ab gente non sequente illes. Clauder tote le reportos contra iste conto. + suspend: Impedir ulle interaction de o a iste conto e deler su contentos. Reversibile intra 30 dies. Clauder tote le reportos contra iste conto. + warning_preset_id: Optional. Tu pote ancora adder personal texto a fin del preconfigurate + announcement: + all_day: Si marcate, solo le datas del campo tempore sera monstrate + ends_at: Le annuncio sera automaticamente obscurate a iste tempore + scheduled_at: Lassar blanc pro publicar le annuncio immediatemente + starts_at: Optional. In caso tu annuncio es ligate con un specific campo tempore + text: Tu pote usar le syntaxe de message. Presta attention al spatio que le annuncio occupara sur le schermo de usator + appeal: + text: Tu pote solo appellar te un vice defaults: + autofollow: Illes qui se inscribe per le invitation automaticamente devenira tu sequaces + avatar: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px + bot: Signala a alteres que le conto principalmente exeque actiones automatisate e poterea non esser surveliate + context: Un o plure contextos ubi le filtro deberea applicar se + current_password: Pro propositos de securitate insere le contrasigno del conto actual + current_username: Pro confirmar, insere le nomine de usator del conto actual + digest: Solo inviate post un longe periodo de inactivitate e solo si tu ha recipite alcun messages personal in tu absentia + email: Te sera inviate un email de confirmation + header: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px + inbox_url: Copia le URL ab le pagina principal del repetitor que tu vole usar password: Usa al minus 8 characteres setting_display_media_hide_all: Sempre celar le medios setting_display_media_show_all: Sempre monstrar le medios username: Tu pote usar litteras, numeros e tractos de sublineamento + ip_block: + severities: + no_access: Blocar accesso a tote le ressources webhook: events: Selige le eventos a inviar url: Ubi le eventos essera inviate @@ -28,6 +74,7 @@ ia: types: disable: Gelar none: Inviar un advertimento + sensitive: Sensibile silence: Limitar suspend: Suspender announcement: @@ -53,10 +100,12 @@ ia: setting_system_font_ui: Usar typo de litteras predefinite del systema setting_theme: Thema de sito setting_trends: Monstrar le tendentias de hodie + severity: Severitate sign_in_token_attempt: Codice de securitate title: Titulo username: Nomine de usator username_or_email: Nomine de usator o e-mail + whole_word: Parola integre featured_tag: name: Hashtag filters: @@ -75,8 +124,13 @@ ia: status_page_url: URL del pagina de stato theme: Thema predefinite trends: Activar tendentias + invite: + comment: Commento ip_block: comment: Commento + ip: IP + severities: + no_access: Blocar le accesso severity: Regula notification_emails: software_updates: @@ -94,11 +148,14 @@ ia: name: Hashtag usable: Permitter al messages usar iste hashtag user: + role: Rolo time_zone: Fuso horari user_role: name: Nomine permissions_as_keys: Permissiones position: Prioritate + webhook: + events: Eventos activate not_recommended: Non recommendate recommended: Recommendate required: diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml index f68eef8a63..9044546f2b 100644 --- a/config/locales/simple_form.pt-BR.yml +++ b/config/locales/simple_form.pt-BR.yml @@ -240,6 +240,7 @@ pt-BR: backups_retention_period: Período de retenção do arquivo de usuário bootstrap_timeline_accounts: Sempre recomendar essas contas para novos usuários closed_registrations_message: Mensagem personalizada quando inscrições não estão disponíveis + content_cache_retention_period: Período de retenção de conteúdo remoto custom_css: CSS personalizável mascot: Mascote personalizado (legado) media_cache_retention_period: Período de retenção do cachê de mídia diff --git a/config/locales/simple_form.sr-Latn.yml b/config/locales/simple_form.sr-Latn.yml index bc4eafb965..6bee31a42c 100644 --- a/config/locales/simple_form.sr-Latn.yml +++ b/config/locales/simple_form.sr-Latn.yml @@ -77,10 +77,13 @@ sr-Latn: warn: Sakrij filtrirani sadržaj iza upozorenja u kome se navodi naziv filtera form_admin_settings: activity_api_enabled: Brojevi lokalno postavljenih objava, aktivnih korisnika i novih registracija na nedeljnoj bazi + backups_retention_period: Korisnici imaju mogućnost da generišu arhive svojih objava za kasnije preuzimanje. Kada se podese na pozitivnu vrednost, ove arhive će se automatski izbrisati iz vašeg skladišta nakon navedenog broja dana. bootstrap_timeline_accounts: Ovi nalozi će biti zakačeni na vrh preporuka za praćenje novih korisnika. closed_registrations_message: Prikazuje se kada su registracije zatvorene + content_cache_retention_period: Sve objave sa drugih servera (uključujući podržavanja i odgovore) će biti izbrisane nakon navedenog broja dana, bez obzira na bilo kakvu interakciju lokalnog korisnika sa tim objavama. Ovo uključuje objave u kojima ih je lokalni korisnik označio kao obeleživače ili omiljene. Privatna pominjanja između korisnika sa različitih instanci će takođe biti izgubljena i nemoguće ih je vratiti. Korišćenje ove postavke je namenjeno za slučajeve posebne namene i krši mnoga očekivanja korisnika kada se primeni za upotrebu opšte namene. custom_css: Možete da primenite prilagođene stilove na veb verziji Mastodon-a. mascot: Zamenjuje ilustraciju u naprednom veb okruženju. + media_cache_retention_period: Medijske datoteke iz objava udaljenih korisnika se keširaju na vašem serveru. Kada se podesi na pozitivnu vrednost, mediji će biti izbrisani nakon navedenog broja dana. Ako se medijski podaci zahtevaju nakon brisanja, biće ponovo preuzeti, ako je izvorni sadržaj i dalje dostupan. Zbog ograničenja koliko često kartice za pregled veza anketiraju sajtove trećih strana, preporučuje se da ovu vrednost postavite na najmanje 14 dana, inače kartice za pregled veza neće biti ažurirane na zahtev pre tog vremena. peers_api_enabled: Lista domena sa kojima se ovaj server susreo u fediverzumu. Ovde nisu sadržani podaci o tome da li se Vaš server federiše sa drugim serverima, već samo da Vaš server zna za njih. Ove informacije koriste servisi koji prikupljaju podatke i vode statistiku o federaciji u širem smislu. profile_directory: Direktorijum profila navodi sve korisnike koji su se opredelili da budu vidljivi. require_invite_text: Kada registracije zahtevaju ručno odobrenje, postavite da odgovor na „Zašto želite da se pridružite?“ bude obavezan, a ne opcionalan @@ -240,6 +243,7 @@ sr-Latn: backups_retention_period: Period čuvanja korisničke arhive bootstrap_timeline_accounts: Uvek preporuči ove naloge novim korisnicima closed_registrations_message: Prilagođena poruka kada prijave nisu moguće + content_cache_retention_period: Period zadržavanja udaljenog sadržaja custom_css: Prilagođeni CSS mascot: Prilagođena maskota (nasleđe) media_cache_retention_period: Period čuvanja keša medija diff --git a/config/locales/simple_form.sr.yml b/config/locales/simple_form.sr.yml index 006f4cf6d2..4ec8374075 100644 --- a/config/locales/simple_form.sr.yml +++ b/config/locales/simple_form.sr.yml @@ -77,10 +77,13 @@ sr: warn: Сакриј филтрирани садржај иза упозорења у коме се наводи назив филтера form_admin_settings: activity_api_enabled: Бројеви локално постављених објава, активних корисника и нових регистрација на недељној бази + backups_retention_period: Корисници имају могућност да генеришу архиве својих објава за касније преузимање. Када се подесе на позитивну вредност, ове архиве ће се аутоматски избрисати из вашег складишта након наведеног броја дана. bootstrap_timeline_accounts: Ови налози ће бити закачени на врх препорука за праћење нових корисника. closed_registrations_message: Приказује се када су регистрације затворене + content_cache_retention_period: Све објаве са других сервера (укључујући подржавања и одговоре) ће бити избрисане након наведеног броја дана, без обзира на било какву интеракцију локалног корисника са тим објавама. Ово укључује објаве у којима их је локални корисник означио као обележиваче или омиљене. Приватна помињања између корисника са различитих инстанци ће такође бити изгубљена и немогуће их је вратити. Коришћење ове поставке је намењено за случајеве посебне намене и крши многа очекивања корисника када се примени за употребу опште намене. custom_css: Можете да примените прилагођене стилове на веб верзији Mastodon-а. mascot: Замењује илустрацију у напредном веб окружењу. + media_cache_retention_period: Медијске датотеке из објава удаљених корисника се кеширају на вашем серверу. Када се подеси на позитивну вредност, медији ће бити избрисани након наведеног броја дана. Ако се медијски подаци захтевају након брисања, биће поново преузети, ако је изворни садржај и даље доступан. Због ограничења колико често картице за преглед веза анкетирају сајтове трећих страна, препоручује се да ову вредност поставите на најмање 14 дана, иначе картице за преглед веза неће бити ажуриране на захтев пре тог времена. peers_api_enabled: Листа домена са којима се овај сервер сусрео у федиверзуму. Овде нису садржани подаци о томе да ли се Ваш сервер федерише са другим серверима, већ само да Ваш сервер зна за њих. Ове информације користе сервиси који прикупљају податке и воде статистику о федерацији у ширем смислу. profile_directory: Директоријум профила наводи све кориснике који су се определили да буду видљиви. require_invite_text: Када регистрације захтевају ручно одобрење, поставите да одговор на „Зашто желите да се придружите?“ буде обавезан, а не опционалан @@ -240,6 +243,7 @@ sr: backups_retention_period: Период чувања корисничке архиве bootstrap_timeline_accounts: Увек препоручи ове налоге новим корисницима closed_registrations_message: Прилагођена порука када пријаве нису могуће + content_cache_retention_period: Период задржавања удаљеног садржаја custom_css: Прилагођени CSS mascot: Прилагођена маскота (наслеђе) media_cache_retention_period: Период чувања кеша медија diff --git a/config/locales/sk.yml b/config/locales/sk.yml index d4cd865854..400059770b 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -236,10 +236,12 @@ sk: confirm_user_html: "%{name} potvrdil/a emailovú adresu používateľa %{target}" create_account_warning_html: "%{name} poslal/a upozornenie užívateľovi %{target}" create_announcement_html: "%{name} vytvoril/a nové oboznámenie %{target}" + create_canonical_email_block_html: "%{name} zablokoval/a email s hašom %{target}" create_custom_emoji_html: "%{name} nahral/a novú emotikonu %{target}" create_domain_allow_html: "%{name} povolil/a federáciu s doménou %{target}" create_domain_block_html: "%{name} zablokoval/a doménu %{target}" create_email_domain_block_html: "%{name} zablokoval/a e-mailovú doménu %{target}" + create_ip_block_html: "%{name} vytvoril/a pravidlo pre IP %{target}" create_user_role_html: "%{name} vytvoril/a rolu pre %{target}" demote_user_html: "%{name} degradoval/a užívateľa %{target}" destroy_announcement_html: "%{name} vymazal/a oboznámenie %{target}" @@ -621,6 +623,7 @@ sk: branding: title: Značka content_retention: + danger_zone: Riziková zóna title: Ponechanie obsahu discovery: follow_recommendations: Odporúčania pre nasledovanie @@ -726,10 +729,16 @@ sk: tags: dashboard: tag_accounts_measure: unikátnych použití + tag_languages_dimension: Najpoužívanejšie jazyky + tag_servers_dimension: Najpoužívanejšie servery tag_servers_measure: iné servery tag_uses_measure: užívateľov celkovo + listable: Môže byť navrhnutý + not_listable: Nebude navrhnutý + not_trendable: Neobjaví sa medzi trendmi not_usable: Nemôže byť použitý title: Populárne štítky + trendable: Môže sa objaviť medzi trendmi trending_rank: 'Populárne #%{rank}' usable: Môže byť použitý title: Trendy @@ -752,6 +761,7 @@ sk: new_appeal: actions: delete_statuses: vymazať ich príspevky + disable: zmraziť ich účet none: varovanie silence: obmedziť ich účet new_pending_account: @@ -888,14 +898,21 @@ sk: strikes: action_taken: Vykonaný zákrok appeal: Namietni + appeal_submitted_at: Námietka odoslaná appeals: submit: Pošli námietku approve_appeal: Schváľ námietku created_at: Dátumom recipient: Adresované pre + reject_appeal: Zamietni námietku title_actions: + disable: Zmrazenie účtu + mark_statuses_as_sensitive: Označenie príspevkov za chúlostivé none: Varovanie + sensitive: Označenie účtu ako chúlostivý silence: Obmedzenie účtu + your_appeal_approved: Tvoja námietka bola schválená + your_appeal_pending: Odoslal si námietku domain_validator: invalid_domain: nieje správny tvar domény edit_profile: @@ -956,7 +973,11 @@ sk: expires_on: Expiruje dňa %{date} title: Triedenia new: + save: Uložiť nový filter title: Pridaj nové triedenie + statuses: + batch: + remove: Odstrániť z filtrovania generic: all: Všetko cancel: Zruš @@ -975,15 +996,28 @@ sk: imports: errors: over_rows_processing_limit: obsahuje viac než %{count} riadkov + too_large: Súbor je príliš veľký + failures: Zlyhaní(a) + imported: Nahrané modes: merge: Spoj dohromady merge_long: Ponechaj existujúce záznamy a pridaj k nim nové overwrite: Prepíš overwrite_long: Nahraď súčasné záznamy novými preface: Môžeš nahrať dáta ktoré si exportoval/a z iného Mastodon serveru, ako sú napríklad zoznamy ľudí ktorých sleduješ, alebo blokuješ. + recent_imports: Nedávne nahrania + states: + finished: Dokončené + unconfirmed: Nepotvrdených + status: Stav success: Tvoje dáta boli nahraté úspešne, a teraz budú spracované v danom čase + titles: + bookmarks: Nahrávanie záložiek + domain_blocking: Nahrávanie blokovaných domén + lists: Nahrávanie zoznamov type_groups: constructive: Sledovania a záložky + destructive: Blokovania a utíšenia types: blocking: Zoznam blokovaných bookmarks: Záložky @@ -1026,6 +1060,9 @@ sk: sign_in_token: emailovým bezpečtnostným kódom webauthn: bezpečnostnými kľúčmi title: História overení + mail_subscriptions: + unsubscribe: + title: Ukonči odber media_attachments: validations: images_and_video: K príspevku ktorý už obsahuje obrázky nemôžeš priložiť video @@ -1121,7 +1158,11 @@ sk: posting_defaults: Východiskové nastavenia príspevkov public_timelines: Verejné časové osi privacy: + privacy: Súkromie + search: Vyhľadávanie title: Súkromie a dosah + privacy_policy: + title: Pravidlá ochrany súkromia reactions: errors: limit_reached: Maximálny počet rôznorodých reakcií bol dosiahnutý @@ -1152,6 +1193,11 @@ sk: status: Stav účtu remote_follow: missing_resource: Nemožno nájsť potrebnú presmerovaciu adresu k tvojmu účtu + rss: + content_warning: 'Varovanie o obsahu:' + descriptions: + account: Verejné príspevky od @%{acct} + tag: 'Verejné príspevky otagované #%{hashtag}' scheduled_statuses: over_daily_limit: Prekročil/a si denný limit %{limit} predplánovaných príspevkov over_total_limit: Prekročil/a si limit %{limit} predplánovaných príspevkov @@ -1203,6 +1249,7 @@ sk: profile: Profil relationships: Sledovania a následovatelia two_factor_authentication: Dvojfázové overenie + webauthn_authentication: Bezpečnostné kľúče severed_relationships: lost_followers: Stratení nasledovatelia lost_follows: Stratené sledovania @@ -1216,11 +1263,13 @@ sk: other: "%{count} obrázky" boosted_from_html: Vyzdvihnuté od %{acct_link} content_warning: 'Varovanie o obsahu: %{warning}' + default_language: Rovnaký ako jazyk rozhrania disallowed_hashtags: few: 'obsah nepovolených haštagov: %{tags}' many: 'obsah nepovolených haštagov: %{tags}' one: 'obsahoval nepovolený haštag: %{tags}' other: 'obsahoval nepovolené haštagy: %{tags}' + edited_at_html: Upravené %{date} errors: in_reply_not_found: Príspevok, na ktorý sa snažíš odpovedať, pravdepodobne neexistuje. open_in_web: Otvor v okne na webe @@ -1245,6 +1294,7 @@ sk: show_thread: Ukáž diskusné vlákno title: '%{name}: „%{quote}"' visibilities: + direct: Súkromne private: Iba pre sledovateľov private_long: Ukáž iba následovateľom public: Verejné @@ -1252,10 +1302,24 @@ sk: unlisted: Nezaradené unlisted_long: Všetci môžu vidieť, ale nieje zaradené do verejnej osi statuses_cleanup: + exceptions: Výnimky + ignore_favs: Ignoruj obľúbené + ignore_reblogs: Ignoruj vyzdvihnutia + keep_direct: Ponechaj súkromné správy keep_pinned: Ponechaj pripnuté príspevky keep_pinned_hint: Nevymaže žiadne s tvojich pripnutých príspevkov + keep_polls: Ponechaj ankety keep_self_bookmark: Ponechaj príspevky, ktoré sú záložkami keep_self_fav: Ponechať príspevky, ktoré si si obľúbil/a + min_age: + '1209600': 2 týždne + '15778476': 6 mesačné + '2629746': 1 mesačné + '31556952': 1 ročné + '5259492': 2 mesačné + '604800': 1 týždeň + '63113904': 2 ročné + '7889238': 3 mesačné stream_entries: sensitive_content: Senzitívny obsah tags: @@ -1282,8 +1346,10 @@ sk: user_mailer: appeal_approved: action: Nastavenia účtu + title: Námietka schválená appeal_rejected: subtitle: Tvoje odvolanie bolo zamietnuté. + title: Námietka zamietnutá backup_ready: explanation: Vyžiadal/a si si úplnú zálohu svojho Mastodon účtu. extra: Teraz je pripravená na stiahnutie! @@ -1291,23 +1357,36 @@ sk: title: Odber archívu failed_2fa: details: 'Tu sú podrobnosti o pokuse o prihlásenie:' + suspicious_sign_in: + change_password: zmeň svoje heslo + title: Nové prihlásenie warning: + appeal: Pošli námietku + reason: 'Dôvod:' subject: disable: Tvoj účet %{acct} bol zamrazený none: Varovanie pre %{acct} silence: Tvoj účet %{acct} bol obmedzený suspend: Tvoj účet %{acct} bol vylúčený title: + delete_statuses: Príspevky vymazané disable: Účet bol zamrazený + mark_statuses_as_sensitive: Príspevky označené za chúlostivé none: Varovanie + sensitive: Účet označený za chúlostivý silence: Účet bol obmedzený suspend: Tvoj účet bol vylúčený welcome: + apps_android_action: Získaj ju na Google Play + apps_ios_action: Stiahni z App Store + apps_step: Stiahni naše oficiálne aplikácie. apps_title: Mastodon aplikácie edit_profile_action: Prispôsob + edit_profile_title: Prispôsob si svoj profil explanation: Tu nájdeš nejaké tipy do začiatku feature_action: Zisti viac follow_action: Nasleduj + follows_title: Koho nasledovať post_title: Vytvor svoj prvý príspevok share_action: Zdieľaj sign_in_action: Prihlás sa diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index e0fe9a710d..b4976f8985 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -765,6 +765,7 @@ sr-Latn: desc_html: Ovo se oslanja na eksterne skripte iz hCaptcha, što može predstavljati zabrinutost za bezbednost i privatnost. Pored toga, ovo može učiniti proces registracije znatno manje dostupnim nekim (posebno osobama sa invaliditetom). Iz ovih razloga, razmotrite alternativne mere kao što je registracija zasnovana na odobrenju ili na pozivu. title: Zahtevaj od novih korisnika da reše CAPTCHA da bi potvrdili svoj nalog content_retention: + danger_zone: Opasna zona preamble: Kontrolišite kako se sadržaj generisan od strane korisnika skladišti na Mastodon-u. title: Zadržavanje sadržaja default_noindex: diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 1c4ffc8c09..aec6d399d5 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -765,6 +765,7 @@ sr: desc_html: Ово се ослања на екстерне скрипте из hCaptcha, што може представљати забринутост за безбедност и приватност. Поред тога, ово може учинити процес регистрације знатно мање доступним неким (посебно особама са инвалидитетом). Из ових разлога, размотрите алтернативне мере као што је регистрација заснована на одобрењу или на позиву. title: Захтевај од нових корисника да реше CAPTCHA да би потврдили свој налог content_retention: + danger_zone: Опасна зона preamble: Контролишите како се садржај генерисан од стране корисника складишти на Mastodon-у. title: Задржавање садржаја default_noindex: From 1e7d5d2957678788fdea8ade77eced98848ff4ff Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 2 May 2024 05:31:41 -0400 Subject: [PATCH 063/658] Update `devise-two-factor` to version 5.0.0 (#28325) Co-authored-by: Claire --- Gemfile | 2 +- Gemfile.lock | 8 +- app/models/concerns/legacy_otp_secret.rb | 77 +++++++++++++++++++ app/models/user.rb | 8 +- config/environments/development.rb | 3 +- config/environments/production.rb | 1 + config/environments/test.rb | 1 + .../20231210154528_add_otp_secret_to_user.rb | 7 ++ ...80905_migrate_devise_two_factor_secrets.rb | 39 ++++++++++ db/schema.rb | 1 + lib/tasks/tests.rake | 18 ++++- spec/models/user_spec.rb | 15 +++- 12 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 app/models/concerns/legacy_otp_secret.rb create mode 100644 db/migrate/20231210154528_add_otp_secret_to_user.rb create mode 100644 db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb diff --git a/Gemfile b/Gemfile index a10613b30b..eb507e9d18 100644 --- a/Gemfile +++ b/Gemfile @@ -31,7 +31,7 @@ gem 'browser' gem 'charlock_holmes', '~> 0.7.7' gem 'chewy', '~> 7.3' gem 'devise', '~> 4.9' -gem 'devise-two-factor', '~> 4.1' +gem 'devise-two-factor' group :pam_authentication, optional: true do gem 'devise_pam_authenticatable2', '~> 9.2' diff --git a/Gemfile.lock b/Gemfile.lock index 3394930e0d..a231785402 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,8 +97,6 @@ GEM activerecord (>= 3.2, < 8.0) rake (>= 10.4, < 14.0) ast (2.4.2) - attr_encrypted (4.0.0) - encryptor (~> 3.0.0) attr_required (1.0.2) awrence (1.2.1) aws-eventstream (1.3.0) @@ -204,9 +202,8 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise-two-factor (4.1.1) + devise-two-factor (5.0.0) activesupport (~> 7.0) - attr_encrypted (>= 1.3, < 5, != 2) devise (~> 4.0) railties (~> 7.0) rotp (~> 6.0) @@ -236,7 +233,6 @@ GEM htmlentities (~> 4.3.3) launchy (~> 2.1) mail (~> 2.7) - encryptor (3.0.0) erubi (1.12.0) et-orbi (1.2.11) tzinfo @@ -842,7 +838,7 @@ DEPENDENCIES database_cleaner-active_record debug (~> 1.8) devise (~> 4.9) - devise-two-factor (~> 4.1) + devise-two-factor devise_pam_authenticatable2 (~> 9.2) discard (~> 1.2) doorkeeper (~> 5.6) diff --git a/app/models/concerns/legacy_otp_secret.rb b/app/models/concerns/legacy_otp_secret.rb new file mode 100644 index 0000000000..466c4ec9bb --- /dev/null +++ b/app/models/concerns/legacy_otp_secret.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +# TODO: This file is here for legacy support during devise-two-factor upgrade. +# It should be removed after all records have been migrated. + +module LegacyOtpSecret + extend ActiveSupport::Concern + + private + + # Decrypt and return the `encrypted_otp_secret` attribute which was used in + # prior versions of devise-two-factor + # @return [String] The decrypted OTP secret + def legacy_otp_secret + return nil unless self[:encrypted_otp_secret] + return nil unless self.class.otp_secret_encryption_key + + hmac_iterations = 2000 # a default set by the Encryptor gem + key = self.class.otp_secret_encryption_key + salt = Base64.decode64(encrypted_otp_secret_salt) + iv = Base64.decode64(encrypted_otp_secret_iv) + + raw_cipher_text = Base64.decode64(encrypted_otp_secret) + # The last 16 bytes of the ciphertext are the authentication tag - we use + # Galois Counter Mode which is an authenticated encryption mode + cipher_text = raw_cipher_text[0..-17] + auth_tag = raw_cipher_text[-16..-1] # rubocop:disable Style/SlicingWithRange + + # this alrorithm lifted from + # https://github.com/attr-encrypted/encryptor/blob/master/lib/encryptor.rb#L54 + + # create an OpenSSL object which will decrypt the AES cipher with 256 bit + # keys in Galois Counter Mode (GCM). See + # https://ruby.github.io/openssl/OpenSSL/Cipher.html + cipher = OpenSSL::Cipher.new('aes-256-gcm') + + # tell the cipher we want to decrypt. Symmetric algorithms use a very + # similar process for encryption and decryption, hence the same object can + # do both. + cipher.decrypt + + # Use a Password-Based Key Derivation Function to generate the key actually + # used for encryptoin from the key we got as input. + cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(key, salt, hmac_iterations, cipher.key_len) + + # set the Initialization Vector (IV) + cipher.iv = iv + + # The tag must be set after calling Cipher#decrypt, Cipher#key= and + # Cipher#iv=, but before calling Cipher#final. After all decryption is + # performed, the tag is verified automatically in the call to Cipher#final. + # + # If the auth_tag does not verify, then #final will raise OpenSSL::Cipher::CipherError + cipher.auth_tag = auth_tag + + # auth_data must be set after auth_tag has been set when decrypting See + # http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-auth_data-3D + # we are not adding any authenticated data but OpenSSL docs say this should + # still be called. + cipher.auth_data = '' + + # #update is (somewhat confusingly named) the method which actually + # performs the decryption on the given chunk of data. Our OTP secret is + # short so we only need to call it once. + # + # It is very important that we call #final because: + # + # 1. The authentication tag is checked during the call to #final + # 2. Block based cipher modes (e.g. CBC) work on fixed size chunks. We need + # to call #final to get it to process the last chunk properly. The output + # of #final should be appended to the decrypted value. This isn't + # required for streaming cipher modes but including it is a best practice + # so that your code will continue to function correctly even if you later + # change to a block cipher mode. + cipher.update(cipher_text) + cipher.final + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 584120cf2e..8bc0b23ce8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -39,6 +39,7 @@ # role_id :bigint(8) # settings :text # time_zone :string +# otp_secret :string # class User < ApplicationRecord @@ -72,6 +73,8 @@ class User < ApplicationRecord devise :two_factor_authenticatable, otp_secret_encryption_key: Rails.configuration.x.otp_secret + include LegacyOtpSecret # Must be after the above `devise` line in order to override the legacy method + devise :two_factor_backupable, otp_number_of_backup_codes: 10 @@ -131,11 +134,6 @@ class User < ApplicationRecord normalizes :time_zone, with: ->(time_zone) { ActiveSupport::TimeZone[time_zone].nil? ? nil : time_zone } normalizes :chosen_languages, with: ->(chosen_languages) { chosen_languages.compact_blank.presence } - # This avoids a deprecation warning from Rails 5.1 - # It seems possible that a future release of devise-two-factor will - # handle this itself, and this can be removed from our User class. - attribute :otp_secret - has_many :session_activations, dependent: :destroy delegate :can?, to: :role diff --git a/config/environments/development.rb b/config/environments/development.rb index a855f5a16b..a3254125c0 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -87,8 +87,7 @@ Rails.application.configure do # Otherwise, use letter_opener, which launches a browser window to view sent mail. config.action_mailer.delivery_method = ENV['HEROKU'] || ENV['VAGRANT'] || ENV['REMOTE_DEV'] ? :letter_opener_web : :letter_opener - # We provide a default secret for the development environment here. - # This value should not be used in production environments! + # TODO: Remove once devise-two-factor data migration complete config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109') # Raise error when a before_action's only/except options reference missing actions diff --git a/config/environments/production.rb b/config/environments/production.rb index 49e02b53d3..6b1101ea1b 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -157,6 +157,7 @@ Rails.application.configure do 'Referrer-Policy' => 'same-origin', } + # TODO: Remove once devise-two-factor data migration complete config.x.otp_secret = ENV.fetch('OTP_SECRET') # Enable DNS rebinding protection and other `Host` header attacks. diff --git a/config/environments/test.rb b/config/environments/test.rb index 13e1973380..49b0c1f303 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -44,6 +44,7 @@ Rails.application.configure do # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + # TODO: Remove once devise-two-factor data migration complete config.x.otp_secret = '100c7faeef00caa29242f6b04156742bf76065771fd4117990c4282b8748ff3d99f8fdae97c982ab5bd2e6756a159121377cce4421f4a8ecd2d67bd7749a3fb4' # Generate random VAPID keys diff --git a/db/migrate/20231210154528_add_otp_secret_to_user.rb b/db/migrate/20231210154528_add_otp_secret_to_user.rb new file mode 100644 index 0000000000..b2ce0a4f79 --- /dev/null +++ b/db/migrate/20231210154528_add_otp_secret_to_user.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddOtpSecretToUser < ActiveRecord::Migration[7.1] + def change + add_column :users, :otp_secret, :string + end +end diff --git a/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb b/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb new file mode 100644 index 0000000000..360e4806da --- /dev/null +++ b/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class MigrateDeviseTwoFactorSecrets < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + class MigrationUser < ApplicationRecord + self.table_name = :users + + devise :two_factor_authenticatable, + otp_secret_encryption_key: Rails.configuration.x.otp_secret + + include LegacyOtpSecret # Must be after the above `devise` line in order to override the legacy method + end + + def up + MigrationUser.reset_column_information + + users_with_otp_enabled.find_each do |user| + # Gets the new value on already-updated users + # Falls back to legacy value on not-yet-migrated users + otp_secret = user.otp_secret + + Rails.logger.debug { "Processing #{user.email}" } + + # This is a no-op for migrated users and updates format for not migrated + user.update!(otp_secret: otp_secret) + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end + + private + + def users_with_otp_enabled + MigrationUser.where(otp_required_for_login: true, otp_secret: nil) + end +end diff --git a/db/schema.rb b/db/schema.rb index a875c6ffc7..11f1a202f7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1199,6 +1199,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.bigint "role_id" t.text "settings" t.string "time_zone" + t.string "otp_secret" t.index ["account_id"], name: "index_users_on_account_id" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id", where: "(created_by_application_id IS NOT NULL)" diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index 0caebf92a1..c8e0312bbd 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -127,6 +127,14 @@ namespace :tests do exit(1) end + # This is checking the attribute rather than the method, to avoid the legacy fallback + # and ensure the data has been migrated + unless Account.find_local('qcuser').user[:otp_secret] == 'anotpsecretthatshouldbeencrypted' + puts "DEBUG: #{Account.find_local('qcuser').user.inspect}" + puts 'OTP secret for user not preserved as expected' + exit(1) + end + puts 'No errors found. Database state is consistent with a successful migration process.' end @@ -213,9 +221,15 @@ namespace :tests do (4, 10, 'kmruser@localhost', now(), now(), false, 'ku', '{en,kmr,ku,ckb}'); INSERT INTO "users" - (id, account_id, email, created_at, updated_at, locale) + (id, account_id, email, created_at, updated_at, locale, + encrypted_otp_secret, encrypted_otp_secret_iv, encrypted_otp_secret_salt, + otp_required_for_login) VALUES - (5, 11, 'qcuser@localhost', now(), now(), 'fr-QC'); + (5, 11, 'qcuser@localhost', now(), now(), 'fr-QC', + E'Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n', + 'rys3THICkr60BoWC', + '_LMkAGvdg7a+sDIKjI3mR2Q==', + true); INSERT INTO "settings" (id, thing_type, thing_id, var, value, created_at, updated_at) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 714d595dc1..fa0a0503a6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -9,14 +9,25 @@ RSpec.describe User do it_behaves_like 'two_factor_backupable' - describe 'otp_secret' do + describe 'legacy_otp_secret' do it 'is encrypted with OTP_SECRET environment variable' do user = Fabricate(:user, encrypted_otp_secret: "Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n", encrypted_otp_secret_iv: 'rys3THICkr60BoWC', encrypted_otp_secret_salt: '_LMkAGvdg7a+sDIKjI3mR2Q==') - expect(user.otp_secret).to eq 'anotpsecretthatshouldbeencrypted' + expect(user.send(:legacy_otp_secret)).to eq 'anotpsecretthatshouldbeencrypted' + end + end + + describe 'otp_secret' do + it 'encrypts the saved value' do + user = Fabricate(:user, otp_secret: '123123123') + + user.reload + + expect(user.otp_secret).to eq '123123123' + expect(user.attributes_before_type_cast[:otp_secret]).to_not eq '123123123' end end From 88882fbbeefe0a5a91985a4c50c44f897e30aabd Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 2 May 2024 05:40:05 -0400 Subject: [PATCH 064/658] Move Rails/HABTM cop out of todo (#30118) --- .rubocop_todo.yml | 8 -------- app/models/concerns/account/associations.rb | 2 +- app/models/status.rb | 2 +- app/models/tag.rb | 2 ++ 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e656578149..25b573017b 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -42,14 +42,6 @@ RSpec/MultipleMemoizedHelpers: RSpec/NestedGroups: Max: 6 -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/HasAndBelongsToMany: - Exclude: - - 'app/models/concerns/account/associations.rb' - - 'app/models/status.rb' - - 'app/models/tag.rb' - Rails/OutputSafety: Exclude: - 'config/initializers/simple_form.rb' diff --git a/app/models/concerns/account/associations.rb b/app/models/concerns/account/associations.rb index b2e9d255fd..1c67b07e51 100644 --- a/app/models/concerns/account/associations.rb +++ b/app/models/concerns/account/associations.rb @@ -62,7 +62,7 @@ module Account::Associations has_many :aliases, class_name: 'AccountAlias', dependent: :destroy, inverse_of: :account # Hashtags - has_and_belongs_to_many :tags + has_and_belongs_to_many :tags # rubocop:disable Rails/HasAndBelongsToMany has_many :featured_tags, -> { includes(:tag) }, dependent: :destroy, inverse_of: :account # Account deletion requests diff --git a/app/models/status.rb b/app/models/status.rb index 2ff803bf0b..0bb5c0ce23 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -82,7 +82,7 @@ class Status < ApplicationRecord has_many :local_reblogged, -> { merge(Account.local) }, through: :reblogs, source: :account has_many :local_bookmarked, -> { merge(Account.local) }, through: :bookmarks, source: :account - has_and_belongs_to_many :tags + has_and_belongs_to_many :tags # rubocop:disable Rails/HasAndBelongsToMany has_one :preview_cards_status, inverse_of: :status, dependent: :delete diff --git a/app/models/tag.rb b/app/models/tag.rb index 58baa48c05..35be921e2d 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -21,8 +21,10 @@ class Tag < ApplicationRecord include Paginable + # rubocop:disable Rails/HasAndBelongsToMany has_and_belongs_to_many :statuses has_and_belongs_to_many :accounts + # rubocop:enable Rails/HasAndBelongsToMany has_many :passive_relationships, class_name: 'TagFollow', inverse_of: :tag, dependent: :destroy has_many :featured_tags, dependent: :destroy, inverse_of: :tag From 616e2f26668d578ae81043a3836e881178d3e806 Mon Sep 17 00:00:00 2001 From: mogaminsk Date: Thu, 2 May 2024 18:40:18 +0900 Subject: [PATCH 065/658] Fix word breaking in filtered notifications badge (#30114) --- app/javascript/styles/mastodon/components.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 51596ec244..12c987a02f 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -10145,6 +10145,7 @@ noscript { font-weight: 500; font-size: 11px; line-height: 16px; + word-break: keep-all; &__badge { background: $ui-button-background-color; From 9e260014c72fa83740d70d2d603e836f86e64b55 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 2 May 2024 14:02:13 +0200 Subject: [PATCH 066/658] Convert `entrypoints/two_factor_authentication` to Typescript (#30105) --- .../entrypoints/two_factor_authentication.js | 119 ----------- .../entrypoints/two_factor_authentication.ts | 197 ++++++++++++++++++ 2 files changed, 197 insertions(+), 119 deletions(-) delete mode 100644 app/javascript/entrypoints/two_factor_authentication.js create mode 100644 app/javascript/entrypoints/two_factor_authentication.ts diff --git a/app/javascript/entrypoints/two_factor_authentication.js b/app/javascript/entrypoints/two_factor_authentication.js deleted file mode 100644 index e77965c757..0000000000 --- a/app/javascript/entrypoints/two_factor_authentication.js +++ /dev/null @@ -1,119 +0,0 @@ -import * as WebAuthnJSON from '@github/webauthn-json'; -import axios from 'axios'; - -import ready from '../mastodon/ready'; -import 'regenerator-runtime/runtime'; - -function getCSRFToken() { - var CSRFSelector = document.querySelector('meta[name="csrf-token"]'); - if (CSRFSelector) { - return CSRFSelector.getAttribute('content'); - } else { - return null; - } -} - -function hideFlashMessages() { - Array.from(document.getElementsByClassName('flash-message')).forEach(function(flashMessage) { - flashMessage.classList.add('hidden'); - }); -} - -function callback(url, body) { - axios.post(url, JSON.stringify(body), { - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'X-CSRF-Token': getCSRFToken(), - }, - credentials: 'same-origin', - }).then(function(response) { - window.location.replace(response.data.redirect_path); - }).catch(function(error) { - if (error.response.status === 422) { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error.response.data.error); - } else { - console.error(error); - } - }); -} - -ready(() => { - if (!WebAuthnJSON.supported()) { - const unsupported_browser_message = document.getElementById('unsupported-browser-message'); - if (unsupported_browser_message) { - unsupported_browser_message.classList.remove('hidden'); - document.querySelector('.btn.js-webauthn').disabled = true; - } - } - - - const webAuthnCredentialRegistrationForm = document.getElementById('new_webauthn_credential'); - if (webAuthnCredentialRegistrationForm) { - webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => { - event.preventDefault(); - - var nickname = event.target.querySelector('input[name="new_webauthn_credential[nickname]"]'); - if (nickname.value) { - axios.get('/settings/security_keys/options') - .then((response) => { - const credentialOptions = response.data; - - WebAuthnJSON.create({ 'publicKey': credentialOptions }).then((credential) => { - var params = { 'credential': credential, 'nickname': nickname.value }; - callback('/settings/security_keys', params); - }).catch((error) => { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error); - }); - }).catch((error) => { - console.error(error.response.data.error); - }); - } else { - nickname.focus(); - } - }); - } - - const webAuthnCredentialAuthenticationForm = document.getElementById('webauthn-form'); - if (webAuthnCredentialAuthenticationForm) { - webAuthnCredentialAuthenticationForm.addEventListener('submit', (event) => { - event.preventDefault(); - - axios.get('sessions/security_key_options') - .then((response) => { - const credentialOptions = response.data; - - WebAuthnJSON.get({ 'publicKey': credentialOptions }).then((credential) => { - var params = { 'user': { 'credential': credential } }; - callback('sign_in', params); - }).catch((error) => { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error); - }); - }).catch((error) => { - console.error(error.response.data.error); - }); - }); - - const otpAuthenticationForm = document.getElementById('otp-authentication-form'); - - const linkToOtp = document.getElementById('link-to-otp'); - linkToOtp.addEventListener('click', () => { - webAuthnCredentialAuthenticationForm.classList.add('hidden'); - otpAuthenticationForm.classList.remove('hidden'); - hideFlashMessages(); - }); - - const linkToWebAuthn = document.getElementById('link-to-webauthn'); - linkToWebAuthn.addEventListener('click', () => { - otpAuthenticationForm.classList.add('hidden'); - webAuthnCredentialAuthenticationForm.classList.remove('hidden'); - hideFlashMessages(); - }); - } -}); diff --git a/app/javascript/entrypoints/two_factor_authentication.ts b/app/javascript/entrypoints/two_factor_authentication.ts new file mode 100644 index 0000000000..981481694b --- /dev/null +++ b/app/javascript/entrypoints/two_factor_authentication.ts @@ -0,0 +1,197 @@ +import * as WebAuthnJSON from '@github/webauthn-json'; +import axios, { AxiosError } from 'axios'; + +import ready from '../mastodon/ready'; + +import 'regenerator-runtime/runtime'; + +type PublicKeyCredentialCreationOptionsJSON = + WebAuthnJSON.CredentialCreationOptionsJSON['publicKey']; + +function exceptionHasAxiosError( + error: unknown, +): error is AxiosError<{ error: unknown }> { + return ( + error instanceof AxiosError && + typeof error.response?.data === 'object' && + 'error' in error.response.data + ); +} + +function logAxiosResponseError(error: unknown) { + if (exceptionHasAxiosError(error)) console.error(error); +} + +function getCSRFToken() { + return document + .querySelector('meta[name="csrf-token"]') + ?.getAttribute('content'); +} + +function hideFlashMessages() { + document.querySelectorAll('.flash-message').forEach((flashMessage) => { + flashMessage.classList.add('hidden'); + }); +} + +async function callback( + url: string, + body: + | { + credential: WebAuthnJSON.PublicKeyCredentialWithAttestationJSON; + nickname: string; + } + | { + user: { credential: WebAuthnJSON.PublicKeyCredentialWithAssertionJSON }; + }, +) { + try { + const response = await axios.post<{ redirect_path: string }>( + url, + JSON.stringify(body), + { + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + 'X-CSRF-Token': getCSRFToken(), + }, + }, + ); + + window.location.replace(response.data.redirect_path); + } catch (error) { + if (error instanceof AxiosError && error.response?.status === 422) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + + logAxiosResponseError(error); + } else { + console.error(error); + } + } +} + +async function handleWebauthnCredentialRegistration(nickname: string) { + try { + const response = await axios.get( + '/settings/security_keys/options', + ); + + const credentialOptions = response.data; + + try { + const credential = await WebAuthnJSON.create({ + publicKey: credentialOptions, + }); + + const params = { + credential: credential, + nickname: nickname, + }; + + await callback('/settings/security_keys', params); + } catch (error) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + console.error(error); + } + } catch (error) { + logAxiosResponseError(error); + } +} + +async function handleWebauthnCredentialAuthentication() { + try { + const response = await axios.get( + 'sessions/security_key_options', + ); + + const credentialOptions = response.data; + + try { + const credential = await WebAuthnJSON.get({ + publicKey: credentialOptions, + }); + + const params = { user: { credential: credential } }; + void callback('sign_in', params); + } catch (error) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + console.error(error); + } + } catch (error) { + logAxiosResponseError(error); + } +} + +ready(() => { + if (!WebAuthnJSON.supported()) { + const unsupported_browser_message = document.getElementById( + 'unsupported-browser-message', + ); + if (unsupported_browser_message) { + unsupported_browser_message.classList.remove('hidden'); + const button = document.querySelector( + 'button.btn.js-webauthn', + ); + if (button) button.disabled = true; + } + } + + const webAuthnCredentialRegistrationForm = + document.querySelector('form#new_webauthn_credential'); + if (webAuthnCredentialRegistrationForm) { + webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => { + event.preventDefault(); + + if (!(event.target instanceof HTMLFormElement)) return; + + const nickname = event.target.querySelector( + 'input[name="new_webauthn_credential[nickname]"]', + ); + + if (nickname?.value) { + void handleWebauthnCredentialRegistration(nickname.value); + } else { + nickname?.focus(); + } + }); + } + + const webAuthnCredentialAuthenticationForm = + document.getElementById('webauthn-form'); + if (webAuthnCredentialAuthenticationForm) { + webAuthnCredentialAuthenticationForm.addEventListener('submit', (event) => { + event.preventDefault(); + void handleWebauthnCredentialAuthentication(); + }); + + const otpAuthenticationForm = document.getElementById( + 'otp-authentication-form', + ); + + const linkToOtp = document.getElementById('link-to-otp'); + + linkToOtp?.addEventListener('click', () => { + webAuthnCredentialAuthenticationForm.classList.add('hidden'); + otpAuthenticationForm?.classList.remove('hidden'); + hideFlashMessages(); + }); + + const linkToWebAuthn = document.getElementById('link-to-webauthn'); + linkToWebAuthn?.addEventListener('click', () => { + otpAuthenticationForm?.classList.add('hidden'); + webAuthnCredentialAuthenticationForm.classList.remove('hidden'); + hideFlashMessages(); + }); + } +}).catch((e: unknown) => { + throw e; +}); From 253ead3aa7f69053eb6b275ba3016c43be2d3675 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 2 May 2024 22:56:21 +0200 Subject: [PATCH 067/658] Fix not being able to block a subdomain of an already-blocked domain through the API (#30119) --- .../api/v1/admin/domain_blocks_controller.rb | 9 +++- .../api/v1/admin/domain_blocks_spec.rb | 41 ++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/admin/domain_blocks_controller.rb b/app/controllers/api/v1/admin/domain_blocks_controller.rb index b589d277d5..ae94ac59cd 100644 --- a/app/controllers/api/v1/admin/domain_blocks_controller.rb +++ b/app/controllers/api/v1/admin/domain_blocks_controller.rb @@ -29,10 +29,11 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController def create authorize :domain_block, :create? + @domain_block = DomainBlock.new(resource_params) existing_domain_block = resource_params[:domain].present? ? DomainBlock.rule_for(resource_params[:domain]) : nil - return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if existing_domain_block.present? + return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if conflicts_with_existing_block?(@domain_block, existing_domain_block) - @domain_block = DomainBlock.create!(resource_params) + @domain_block.save! DomainBlockWorker.perform_async(@domain_block.id) log_action :create, @domain_block render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer @@ -55,6 +56,10 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController private + def conflicts_with_existing_block?(domain_block, existing_domain_block) + existing_domain_block.present? && (existing_domain_block.domain == TagManager.instance.normalize_domain(domain_block.domain) || !domain_block.stricter_than?(existing_domain_block)) + end + def set_domain_blocks @domain_blocks = filtered_domain_blocks.order(id: :desc).to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) end diff --git a/spec/requests/api/v1/admin/domain_blocks_spec.rb b/spec/requests/api/v1/admin/domain_blocks_spec.rb index 47aaf44d80..415281a932 100644 --- a/spec/requests/api/v1/admin/domain_blocks_spec.rb +++ b/spec/requests/api/v1/admin/domain_blocks_spec.rb @@ -130,7 +130,7 @@ RSpec.describe 'Domain Blocks' do it_behaves_like 'forbidden for wrong role', '' it_behaves_like 'forbidden for wrong role', 'Moderator' - it 'returns expected domain name and severity', :aggregate_failures do + it 'creates a domain block with the expected domain name and severity', :aggregate_failures do subject body = body_as_json @@ -146,7 +146,44 @@ RSpec.describe 'Domain Blocks' do expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present end - context 'when a stricter domain block already exists' do + context 'when a looser domain block already exists on a higher level domain' do + let(:params) { { domain: 'foo.bar.com', severity: :suspend } } + + before do + Fabricate(:domain_block, domain: 'bar.com', severity: :silence) + end + + it 'creates a domain block with the expected domain name and severity', :aggregate_failures do + subject + + body = body_as_json + + expect(response).to have_http_status(200) + expect(body).to match a_hash_including( + { + domain: 'foo.bar.com', + severity: 'suspend', + } + ) + + expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present + end + end + + context 'when a domain block already exists on the same domain' do + before do + Fabricate(:domain_block, domain: 'foo.bar.com', severity: :silence) + end + + it 'returns existing domain block in error', :aggregate_failures do + subject + + expect(response).to have_http_status(422) + expect(body_as_json[:existing_domain_block][:domain]).to eq('foo.bar.com') + end + end + + context 'when a stricter domain block already exists on a higher level domain' do before do Fabricate(:domain_block, domain: 'bar.com', severity: :suspend) end From 4b2054ee57b41c304f85eab6236baebe0b732d95 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 23:22:26 +0200 Subject: [PATCH 068/658] Update Yarn to v4.2.1 (#30153) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- streaming/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 24d81ea476..3abc11c34b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/mastodon", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.1.1", + "packageManager": "yarn@4.2.1", "engines": { "node": ">=18" }, diff --git a/streaming/package.json b/streaming/package.json index a0e7d96bb5..c4dcccf1f5 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/streaming", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.1.1", + "packageManager": "yarn@4.2.1", "engines": { "node": ">=18" }, From 9380805fc15f0a0bfc4ed9e70c393191f64e2718 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 May 2024 10:48:09 +0200 Subject: [PATCH 069/658] Update dependency rubocop-rspec to v2.29.2 (#30158) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a231785402..cb36bc2ddc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -651,8 +651,8 @@ GEM rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.2) - parser (>= 3.3.0.4) + rubocop-ast (1.31.3) + parser (>= 3.3.1.0) rubocop-capybara (2.20.0) rubocop (~> 1.41) rubocop-factory_bot (2.25.1) @@ -665,7 +665,7 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (2.29.1) + rubocop-rspec (2.29.2) rubocop (~> 1.40) rubocop-capybara (~> 2.17) rubocop-factory_bot (~> 2.22) From d5444a2c6c6bf9597503297dba9181e6d9bfad46 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 May 2024 11:15:06 +0200 Subject: [PATCH 070/658] New Crowdin Translations (automated) (#30160) Co-authored-by: GitHub Actions --- config/locales/ia.yml | 52 +++++++++++++++++++++++++++ config/locales/simple_form.ia.yml | 60 +++++++++++++++++++++++++++++++ config/locales/simple_form.sv.yml | 4 +++ 3 files changed, 116 insertions(+) diff --git a/config/locales/ia.yml b/config/locales/ia.yml index ff7b47c1fe..59dd2dbc0f 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -159,42 +159,94 @@ ia: undo_suspension: Disfacer le suspension unsilenced_msg: Le limite del conto de %{username} ha essite cancellate unsubscribe: Desubscriber + unsuspended_msg: Annullate suspension del conto %{username} con successo username: Nomine de usator view_domain: Vider summario de dominio warn: Avisar web: Web + whitelisted: Permittite pro federation action_logs: action_types: + approve_appeal: Approbar appello + approve_user: Approbar usator + assigned_to_self_report: Assignar reporto change_email_user: Cambiar e-mail pro le usator change_role_user: Cambiar le rolo del usator confirm_user: Confirmar le usator create_account_warning: Crear un advertimento create_announcement: Crear annuncio + create_canonical_email_block: Crear blocada de email + create_custom_emoji: Crear emoticone personalisate + create_domain_allow: Crear permisso de dominio + create_domain_block: Crear blocada de dominio + create_email_domain_block: Crear blocada de dominio email create_ip_block: Crear un regula IP + create_unavailable_domain: Crear dominio indisponibile create_user_role: Crear un rolo + demote_user: Degradar usator destroy_announcement: Deler annuncio + destroy_canonical_email_block: Deler blocada de email + destroy_custom_emoji: Deler emoticone personalisate + destroy_domain_allow: Deler permisso de dominio + destroy_domain_block: Deler blocada de dominio + destroy_email_domain_block: Crear blocada de dominio email + destroy_instance: Purgar dominio destroy_ip_block: Deler le regula IP destroy_status: Deler le message destroy_unavailable_domain: Deler le dominio non disponibile + destroy_user_role: Destruer rolo disable_2fa_user: Disactivar 2FA disable_custom_emoji: Disactivar emoji personalisate + disable_sign_in_token_auth_user: Disactivar le authentication per testimonio via email pro usator disable_user: Disactivar le usator enable_custom_emoji: Activar emoji personalisate + enable_sign_in_token_auth_user: Activar le authentication per testimonio via email pro usator enable_user: Activar le usator + memorialize_account: Commemorar conto promote_user: Promover usator + reject_appeal: Rejectar appello + reject_user: Rejectar usator + remove_avatar_user: Remover avatar + reopen_report: Reaperir reporto resend_user: Reinviar message de confirmation reset_password_user: Reinitialisar contrasigno + resolve_report: Resolver reporto + sensitive_account: Marcar como sensibile le medios del conto silence_account: Limitar conto + suspend_account: Suspender conto + unassigned_report: Disassignar reporto unblock_email_account: Disblocar adresse de e-mail + unsensitive_account: Dismarcar como sensibile le medios del conto unsilence_account: Disfacer le limite de conto + unsuspend_account: Annullar suspension de conto update_announcement: Actualisar annuncio update_custom_emoji: Actualisar emoji personalisate + update_domain_block: Actualisar blocada de dominio update_ip_block: Actualisar le regula IP update_status: Actualisar le message update_user_role: Actualisar rolo actions: + approve_appeal_html: "%{name} approbava appello del decision de moderation de %{target}" + approve_user_html: "%{name} approbava inscription de %{target}" + assigned_to_self_report_html: "%{name} assignava reporto %{target} a se mesme" change_email_user_html: "%{name} cambiava le adresse de e-mail address del usator %{target}" + change_role_user_html: "%{name} cambiava rolo de %{target}" + confirm_user_html: "%{name} confirmava le adresse email del usator %{target}" + create_account_warning_html: "%{name} inviava un advertimento a %{target}" create_announcement_html: "%{name} creava un nove annuncio %{target}" + create_canonical_email_block_html: "%{name} blocava email con le hash %{target}" + create_custom_emoji_html: "%{name} cargava nove emoticone %{target}" + create_domain_allow_html: "%{name} permitteva federation con dominio %{target}" + create_domain_block_html: "%{name} blocava dominio %{target}" + create_email_domain_block_html: "%{name} blocava dominio email %{target}" + create_ip_block_html: "%{name} creava regula pro IP %{target}" + create_unavailable_domain_html: "%{name} stoppava consignation a dominio %{target}" + create_user_role_html: "%{name} creava rolo de %{target}" + demote_user_html: "%{name} degradava usator %{target}" + destroy_announcement_html: "%{name} deleva annuncio %{target}" + destroy_custom_emoji_html: "%{name} deleva emoji %{target}" + destroy_domain_block_html: "%{name} disblocava dominio %{target}" + destroy_user_role_html: "%{name} deleva le rolo de %{target}" deleted_account: conto delite announcements: destroyed_msg: Annuncio delite con successo! diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index 05a5fa5013..b5ec14e60e 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -48,10 +48,48 @@ ia: email: Te sera inviate un email de confirmation header: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px inbox_url: Copia le URL ab le pagina principal del repetitor que tu vole usar + irreversible: Le messages filtrate disparera irreversibilemente, mesmo si le filtro es plus tarde removite + locale: Le lingua del interfacie de usator, del emails e del notificationes pulsate password: Usa al minus 8 characteres + phrase: Sera concordate ignorante majuscule/minuscule in le texto o avisos de contento de un message + scopes: A que APIs sera permittite acceder al application. Si tu selige un ambito de maxime nivello, tu non besonia de seliger los singulemente. + setting_aggregate_reblogs: Non monstra nove stimulos pro messages que ha essite recentemente stimulate (stimulos solo affice los novemente recipite) + setting_always_send_emails: Normalmente le avisos de email non sera inviate quando tu activemente usa Mastodon + setting_default_sensitive: Le medios sensibile es celate de ordinario e pote esser revelate con un clic + setting_display_media_default: Celar le medios marcate como sensibile setting_display_media_hide_all: Sempre celar le medios setting_display_media_show_all: Sempre monstrar le medios + setting_use_blurhash: Le imagines degradate es basate sur le colores del medios visual celate, ma illos offusca qualcunque detalios + setting_use_pending_items: Celar le classification temporal detra un clic in vice que automaticamente rolante le fluxo username: Tu pote usar litteras, numeros e tractos de sublineamento + whole_word: Quando le parola o expression clave es solo alphanumeric, illo sera solo applicate si illo concorda con tote le parola + domain_allow: + domain: Iste dominio potera reportar datos ab iste servitor e le datos in ingresso ab illo sera processate e immagazinate + email_domain_block: + domain: Isto pote esser le nomine de dominio que apparera in le adresse email o le registration MX que illo usa. Illos sera verificate durante le inscription. + with_dns_records: Un tentativa sera facite pro resolver le registrationes de DNS del dominio date e le resultatos sera alsi blocate + featured_tag: + name: 'Ecce alcun del hashtags que tu usava le plus recentemente:' + filters: + action: Selige que action exequer quando un message concorda con le filtro + actions: + hide: Completemente celar le contento filtrate, comportar se como si illo non existerea + warn: Celar le contento filtrate detra un aviso citante le titulo del filtro + form_admin_settings: + activity_api_enabled: Numeros de messages localmente publicate, usatores active, e nove registrationes in gruppos septimanal + backups_retention_period: Le usatores pote generar archivos de lor messages pro discargar los plus tarde. Quando predefinite a un valor positive, iste archivos sera automaticamente delite de tu immagazinage post le specificate numero de dies. + bootstrap_timeline_accounts: Iste contos sera appunctate al summitate del recommendationes a sequer del nove usatores. + closed_registrations_message: Monstrate quando le inscriptiones es claudite + content_cache_retention_period: Tote messages de altere servitores (includite stimulos e responsas) sera delite post le specificate numero de dies, sin considerar alcun interaction de usator local con ille messages. Isto include messages ubi un usator local los ha marcate como marcapaginas o favoritos. Mentiones private inter usatores de differente instantias sera alsi perdite e impossibile a restaurar. Le uso de iste parametros es intendite pro specific instantias e infringe multe expectationes de usator quando implementate pro uso general. + custom_css: Tu pote applicar stilos personalisate sur le version de web de Mastodon. + mascot: Illo substitue le illustration in le interfacie web avantiate. + media_cache_retention_period: Le files multimedial de messages producite per usatores remote es in cache sur tu servitor. Quando predefinite a un valor positive, le medios sera delite post le numero de dies specificate. Le datos multimedial requirite post que illo es delite, sera re-discargate, si le contento original sera ancora disponibile. Per limitationes sur le frequentia con que le schedas de pre-visualisation de ligamine scruta le sitos de tertie partes, il es recommendate de predefinir iste valor a al minus 14 dies, o le schedas de pre-visualisation de ligamine non sera actualisate sur demanda ante ille tempore. + peers_api_enabled: Un lista de nomines de dominio que iste servitor ha incontrate in le fediverso. Nulle datos es includite ci re tu federation con un date servitor, justo que tu servitor lo cognosce. Isto es usate per servicios que collige statistica re le federation in senso general. + profile_directory: Le directorio de profilo lista tote le usatores qui ha optate pro esser detectabile. + require_invite_text: Quando le inscriptiones require approbation manual, rende obligatori, plus tosto que optional, le entrata de texto “Perque vole tu junger te?” + site_contact_email: Como pote contactar te le personas pro questiones legal o de supporto. + site_contact_username: Como pote contactar te le personas re Mastodon. + site_extended_description: Qualcunque information additional que pote esser utile al visitatores e a tu usatores. Pote esser structurate con syntaxe de markdown. ip_block: severities: no_access: Blocar accesso a tote le ressources @@ -68,8 +106,11 @@ ia: show_collections: Monstrar sequites e sequitores in le profilo unlocked: Acceptar automaticamente nove sequitores account_warning_preset: + text: Texto predefinite title: Titulo admin_account_action: + send_email_notification: Notificar le usator per e-mail + text: Advertimento personalisate type: Action types: disable: Gelar @@ -78,6 +119,7 @@ ia: silence: Limitar suspend: Suspender announcement: + starts_at: Initio del evento text: Annuncio defaults: autofollow: Invitar a sequer tu conto @@ -85,24 +127,38 @@ ia: chosen_languages: Filtrar linguas confirm_new_password: Confirmar nove contrasigno confirm_password: Confirmar contrasigno + context: Contextos del filtro current_password: Contrasigno actual + data: Datos display_name: Nomine a monstrar email: Adresse de e-mail + expires_in: Expira post + fields: Campos extra + header: Imagine titulo + honeypot: "%{label} (non compilar)" + inbox_url: URL del cassa de ingresso de repetitor locale: Lingua de interfacie + max_uses: Numero max de usos new_password: Nove contrasigno + note: Bio + otp_attempt: Codice a duo factores password: Contrasigno + phrase: Parola o phrase clave setting_advanced_layout: Activar le interfacie web avantiate setting_always_send_emails: Sempre inviar notificationes per e-mail setting_default_language: Lingua de publication + setting_display_media: Visualisation de medios setting_display_media_default: Predefinite setting_display_media_hide_all: Celar toto setting_display_media_show_all: Monstrar toto setting_system_font_ui: Usar typo de litteras predefinite del systema setting_theme: Thema de sito setting_trends: Monstrar le tendentias de hodie + setting_use_pending_items: Modo lente severity: Severitate sign_in_token_attempt: Codice de securitate title: Titulo + type: Importar le typo username: Nomine de usator username_or_email: Nomine de usator o e-mail whole_word: Parola integre @@ -123,6 +179,7 @@ ia: site_title: Nomine de servitor status_page_url: URL del pagina de stato theme: Thema predefinite + thumbnail: Miniatura de servitor trends: Activar tendentias invite: comment: Commento @@ -133,6 +190,7 @@ ia: no_access: Blocar le accesso severity: Regula notification_emails: + digest: Inviar emails compendio software_updates: all: Notificar sur tote le actualisationes critical: Notificar solmente sur actualisationes critic @@ -156,8 +214,10 @@ ia: position: Prioritate webhook: events: Eventos activate + 'no': 'No' not_recommended: Non recommendate recommended: Recommendate required: + mark: "*" text: requirite 'yes': Si diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml index 3ab16bf69b..5e5c6f9549 100644 --- a/config/locales/simple_form.sv.yml +++ b/config/locales/simple_form.sv.yml @@ -77,10 +77,13 @@ sv: warn: Dölj det filtrerade innehållet bakom en varning som visar filtrets rubrik form_admin_settings: activity_api_enabled: Antalet lokalt publicerade inlägg, aktiva användare och nya registrerade konton per vecka + backups_retention_period: Användare har möjlighet att generera arkiv av sina inlägg för att ladda ned senare. När det sätts till ett positivt värde raderas dessa arkiv automatiskt från din lagring efter det angivna antalet dagar. bootstrap_timeline_accounts: Dessa konton kommer fästas högst upp i nya användares följrekommendationer. closed_registrations_message: Visas när nyregistreringar är avstängda + content_cache_retention_period: Alla inlägg från andra servrar (inklusive booster och svar) kommer att raderas efter det angivna antalet dagar, utan hänsyn till någon lokal användarinteraktion med dessa inlägg. Detta inkluderar inlägg där en lokal användare har markerat det som bokmärke eller favoriter. Privata omnämnanden mellan användare från olika instanser kommer också att gå förlorade och blir omöjliga att återställa. Användningen av denna inställning är avsedd för specialfall och bryter många användarförväntningar när de implementeras för allmänt bruk. custom_css: Du kan använda anpassade stilar på webbversionen av Mastodon. mascot: Åsidosätter illustrationen i det avancerade webbgränssnittet. + media_cache_retention_period: Mediafiler från inlägg som gjorts av fjärranvändare cachas på din server. När inställd på ett positivt värde kommer media att raderas efter det angivna antalet dagar. Om mediadatat begärs efter att det har raderats, kommer det att laddas ned igen om källinnehållet fortfarande är tillgängligt. På grund av begränsningar för hur ofta förhandsgranskningskort för länkar hämtas från tredjepartswebbplatser, rekommenderas det att ange detta värde till minst 14 dagar, annars kommer förhandsgranskningskorten inte att uppdateras på begäran före den tiden. peers_api_enabled: En lista över domänen den här servern har stött på i fediversum. Ingen data inkluderas om du har federerat med servern, bara att din server känner till den. Detta används av tjänster som samlar statistik om federering i allmänhet. profile_directory: Profilkatalogen visar alla användare som har samtyckt till att bli upptäckbara. require_invite_text: Gör fältet "Varför vill du gå med?" obligatoriskt när nyregistreringar kräver manuellt godkännande @@ -240,6 +243,7 @@ sv: backups_retention_period: Lagringsperiod för användararkivet bootstrap_timeline_accounts: Rekommendera alltid dessa konton till nya användare closed_registrations_message: Anpassat meddelande när nyregistreringar inte är tillgängliga + content_cache_retention_period: Förvaringsperiod för fjärrinnehåll custom_css: Anpassad CSS mascot: Anpassad maskot (tekniskt arv) media_cache_retention_period: Tid för bibehållande av mediecache From 9aa31be8d3fd7f20a537bfb08b5e4ef11f636c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= <842+raucao@users.noreply.github.com> Date: Fri, 3 May 2024 11:22:48 +0200 Subject: [PATCH 071/658] Fix local account search on LDAP login being case-sensitive (#30113) Co-authored-by: Claire --- app/models/concerns/user/ldap_authenticable.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/concerns/user/ldap_authenticable.rb b/app/models/concerns/user/ldap_authenticable.rb index 180df9d310..c8e9fa9348 100644 --- a/app/models/concerns/user/ldap_authenticable.rb +++ b/app/models/concerns/user/ldap_authenticable.rb @@ -22,7 +22,7 @@ module User::LdapAuthenticable safe_username = safe_username.gsub(keys, replacement) end - resource = joins(:account).find_by(accounts: { username: safe_username }) + resource = joins(:account).merge(Account.where(Account.arel_table[:username].lower.eq safe_username.downcase)).take if resource.blank? resource = new( From 33368e3e79a6edfcaf65fd2b80b636a7c1e56e48 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 3 May 2024 11:26:24 +0200 Subject: [PATCH 072/658] Change ActiveRecordEncryption variable to be more explicit (#30151) --- config/initializers/active_record_encryption.rb | 4 ++-- lib/tasks/db.rake | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb index f99585b4ad..7cda8c621c 100644 --- a/config/initializers/active_record_encryption.rb +++ b/config/initializers/active_record_encryption.rb @@ -6,9 +6,9 @@ ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY ).each do |key| ENV.fetch(key) do - raise <<~MESSAGE + abort <<~MESSAGE - The ActiveRecord encryption feature requires that these variables are set: + Mastodon now requires that these variables are set: - ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY - ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 4208c2ae4b..07de087766 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -1,6 +1,22 @@ # frozen_string_literal: true +# We are providing our own task with our own format +Rake::Task['db:encryption:init'].clear + namespace :db do + namespace :encryption do + desc 'Generate a set of keys for configuring Active Record encryption in a given environment' + task init: :environment do + puts <<~MSG + Add these environment variables to your Mastodon environment:#{' '} + + ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=#{SecureRandom.alphanumeric(32)} + ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=#{SecureRandom.alphanumeric(32)} + ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=#{SecureRandom.alphanumeric(32)} + MSG + end + end + namespace :migrate do desc 'Setup the db or migrate depending on state of db' task setup: :environment do From b7902225d698a107df2cf8b4ca221caad38fa464 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 3 May 2024 10:56:48 -0400 Subject: [PATCH 073/658] Use built-in github annotation output for `stylelint` (#30165) --- .github/stylelint-matcher.json | 21 --------------------- .github/workflows/lint-css.yml | 6 +----- 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 .github/stylelint-matcher.json diff --git a/.github/stylelint-matcher.json b/.github/stylelint-matcher.json deleted file mode 100644 index cdfd4086bd..0000000000 --- a/.github/stylelint-matcher.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "problemMatcher": [ - { - "owner": "stylelint", - "pattern": [ - { - "regexp": "^([^\\s].*)$", - "file": 1 - }, - { - "regexp": "^\\s+((\\d+):(\\d+))?\\s+(✖|×)\\s+(.*)\\s{2,}(.*)$", - "line": 2, - "column": 3, - "message": 5, - "code": 6, - "loop": true - } - ] - } - ] -} diff --git a/.github/workflows/lint-css.yml b/.github/workflows/lint-css.yml index e5f4874877..d3b8035cd8 100644 --- a/.github/workflows/lint-css.yml +++ b/.github/workflows/lint-css.yml @@ -38,9 +38,5 @@ jobs: - name: Set up Javascript environment uses: ./.github/actions/setup-javascript - - uses: xt0rted/stylelint-problem-matcher@v1 - - - run: echo "::add-matcher::.github/stylelint-matcher.json" - - name: Stylelint - run: yarn lint:css + run: yarn lint:css -f github From 333905b2d54b33b6c0e1103ecb5c113ab77843a0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 24 Apr 2024 10:45:12 +0200 Subject: [PATCH 074/658] [Glitch] Change mute options to be in dropdown on muted users list in web UI Port 74012831f61a36b7f52540c5ccafa0f9692a6596 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/components/account.jsx | 278 +++++++++--------- .../flavours/glitch/styles/components.scss | 14 +- 2 files changed, 153 insertions(+), 139 deletions(-) diff --git a/app/javascript/flavours/glitch/components/account.jsx b/app/javascript/flavours/glitch/components/account.jsx index 7e5209653e..326d4fcb69 100644 --- a/app/javascript/flavours/glitch/components/account.jsx +++ b/app/javascript/flavours/glitch/components/account.jsx @@ -1,16 +1,18 @@ import PropTypes from 'prop-types'; +import { useCallback } from 'react'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import classNames from 'classnames'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; +import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import { EmptyAccount } from 'flavours/glitch/components/empty_account'; import { ShortNumber } from 'flavours/glitch/components/short_number'; import { VerifiedBadge } from 'flavours/glitch/components/verified_badge'; +import DropdownMenuContainer from '../containers/dropdown_menu_container'; import { me } from '../initial_state'; import { Avatar } from './avatar'; @@ -30,153 +32,153 @@ const messages = defineMessages({ unmute_notifications: { id: 'account.unmute_notifications_short', defaultMessage: 'Unmute notifications' }, mute: { id: 'account.mute_short', defaultMessage: 'Mute' }, block: { id: 'account.block_short', defaultMessage: 'Block' }, + more: { id: 'status.more', defaultMessage: 'More' }, }); -class Account extends ImmutablePureComponent { +const Account = ({ size = 46, account, onFollow, onBlock, onMute, onMuteNotifications, hidden, minimal, defaultAction, withBio }) => { + const intl = useIntl(); - static propTypes = { - size: PropTypes.number, - account: ImmutablePropTypes.record, - onFollow: PropTypes.func, - onBlock: PropTypes.func, - onMute: PropTypes.func, - onMuteNotifications: PropTypes.func, - intl: PropTypes.object.isRequired, - hidden: PropTypes.bool, - minimal: PropTypes.bool, - defaultAction: PropTypes.string, - withBio: PropTypes.bool, - }; + const handleFollow = useCallback(() => { + onFollow(account); + }, [onFollow, account]); - static defaultProps = { - size: 46, - }; + const handleBlock = useCallback(() => { + onBlock(account); + }, [onBlock, account]); - handleFollow = () => { - this.props.onFollow(this.props.account); - }; + const handleMute = useCallback(() => { + onMute(account); + }, [onMute, account]); - handleBlock = () => { - this.props.onBlock(this.props.account); - }; + const handleMuteNotifications = useCallback(() => { + onMuteNotifications(account, true); + }, [onMuteNotifications, account]); - handleMute = () => { - this.props.onMute(this.props.account); - }; + const handleUnmuteNotifications = useCallback(() => { + onMuteNotifications(account, false); + }, [onMuteNotifications, account]); - handleMuteNotifications = () => { - this.props.onMuteNotifications(this.props.account, true); - }; - - handleUnmuteNotifications = () => { - this.props.onMuteNotifications(this.props.account, false); - }; - - render () { - const { account, intl, hidden, withBio, defaultAction, size, minimal } = this.props; - - if (!account) { - return ; - } - - if (hidden) { - return ( - <> - {account.get('display_name')} - {account.get('username')} - - ); - } - - let buttons; - - if (account.get('id') !== me && account.get('relationship', null) !== null) { - const following = account.getIn(['relationship', 'following']); - const requested = account.getIn(['relationship', 'requested']); - const blocking = account.getIn(['relationship', 'blocking']); - const muting = account.getIn(['relationship', 'muting']); - - if (requested) { - buttons =
+
+ + + ); +}; + +Card.propTypes = { + id: PropTypes.string.isRequired, + source: PropTypes.oneOf(['friends_of_friends', 'similar_to_recently_followed', 'featured', 'most_followed', 'most_interactions']), +}; diff --git a/app/javascript/flavours/glitch/features/explore/suggestions.jsx b/app/javascript/flavours/glitch/features/explore/suggestions.jsx index 1590e19aba..18a40c28b6 100644 --- a/app/javascript/flavours/glitch/features/explore/suggestions.jsx +++ b/app/javascript/flavours/glitch/features/explore/suggestions.jsx @@ -10,9 +10,10 @@ import { connect } from 'react-redux'; import { fetchSuggestions, dismissSuggestion } from 'flavours/glitch/actions/suggestions'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; -import AccountCard from 'flavours/glitch/features/directory/components/account_card'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; +import { Card } from './components/card'; + const mapStateToProps = state => ({ suggestions: state.getIn(['suggestions', 'items']), isLoading: state.getIn(['suggestions', 'isLoading']), @@ -59,7 +60,11 @@ class Suggestions extends PureComponent { return (
{isLoading ? : suggestions.map(suggestion => ( - + ))}
); diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 3a5420c35c..a52f384657 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -2229,7 +2229,10 @@ a .account__avatar { display: flex; align-items: center; gap: 8px; +} +.account__relationship, +.explore__suggestions__card { .icon-button { border: 1px solid var(--background-border-color); border-radius: 4px; @@ -3178,6 +3181,75 @@ $ui-header-logo-wordmark-width: 99px; display: none; } +.explore__suggestions__card { + padding: 12px 16px; + gap: 8px; + display: flex; + flex-direction: column; + border-bottom: 1px solid var(--background-border-color); + + &:last-child { + border-bottom: 0; + } + + &__source { + padding-inline-start: 60px; + font-size: 13px; + line-height: 16px; + color: $dark-text-color; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + + &__body { + display: flex; + gap: 12px; + align-items: center; + + &__main { + flex: 1 1 auto; + display: flex; + flex-direction: column; + gap: 8px; + min-width: 0; + + &__name-button { + display: flex; + align-items: center; + gap: 8px; + + &__name { + display: block; + color: inherit; + text-decoration: none; + flex: 1 1 auto; + min-width: 0; + } + + .button { + min-width: 80px; + } + + .display-name { + font-size: 15px; + line-height: 20px; + color: $secondary-text-color; + + strong { + font-weight: 700; + } + + &__account { + color: $darker-text-color; + display: block; + } + } + } + } + } +} + @media screen and (max-width: $no-gap-breakpoint - 1px) { .columns-area__panels__pane--compositional { display: none; @@ -7874,10 +7946,11 @@ img.modal-warning { content: ''; position: absolute; bottom: -1px; - left: 0; - width: 100%; + left: 50%; + transform: translateX(-50%); + width: 40px; height: 3px; - border-radius: 4px; + border-radius: 4px 4px 0 0; background: $highlight-text-color; } } From aac59a34ed120ad269aad70fb6600782cdd2bae8 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 25 Apr 2024 19:26:05 +0200 Subject: [PATCH 076/658] [Glitch] Add in-app notifications for moderation actions/warnings Port 4ef0b48b951d65920d3a3d9cdfd099967c5e4f6d to glitch-soc Signed-off-by: Claire --- .../components/moderation_warning.tsx | 78 +++++++++++++++++++ .../notifications/components/notification.jsx | 25 ++++++ .../flavours/glitch/reducers/notifications.js | 1 + .../flavours/glitch/styles/components.scss | 3 +- 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 app/javascript/flavours/glitch/features/notifications/components/moderation_warning.tsx diff --git a/app/javascript/flavours/glitch/features/notifications/components/moderation_warning.tsx b/app/javascript/flavours/glitch/features/notifications/components/moderation_warning.tsx new file mode 100644 index 0000000000..28c3aa1984 --- /dev/null +++ b/app/javascript/flavours/glitch/features/notifications/components/moderation_warning.tsx @@ -0,0 +1,78 @@ +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import WarningIcon from '@/material-icons/400-24px/warning-fill.svg?react'; +import { Icon } from 'flavours/glitch/components/icon'; + +// This needs to be kept in sync with app/models/account_warning.rb +const messages = defineMessages({ + none: { + id: 'notification.moderation_warning.action_none', + defaultMessage: 'Your account has received a moderation warning.', + }, + disable: { + id: 'notification.moderation_warning.action_disable', + defaultMessage: 'Your account has been disabled.', + }, + mark_statuses_as_sensitive: { + id: 'notification.moderation_warning.action_mark_statuses_as_sensitive', + defaultMessage: 'Some of your posts have been marked as sensitive.', + }, + delete_statuses: { + id: 'notification.moderation_warning.action_delete_statuses', + defaultMessage: 'Some of your posts have been removed.', + }, + sensitive: { + id: 'notification.moderation_warning.action_sensitive', + defaultMessage: 'Your posts will be marked as sensitive from now on.', + }, + silence: { + id: 'notification.moderation_warning.action_silence', + defaultMessage: 'Your account has been limited.', + }, + suspend: { + id: 'notification.moderation_warning.action_suspend', + defaultMessage: 'Your account has been suspended.', + }, +}); + +interface Props { + action: + | 'none' + | 'disable' + | 'mark_statuses_as_sensitive' + | 'delete_statuses' + | 'sensitive' + | 'silence' + | 'suspend'; + id: string; + hidden: boolean; +} + +export const ModerationWarning: React.FC = ({ action, id, hidden }) => { + const intl = useIntl(); + + if (hidden) { + return null; + } + + return ( + + + +
+

{intl.formatMessage(messages[action])}

+ + + +
+
+ ); +}; diff --git a/app/javascript/flavours/glitch/features/notifications/components/notification.jsx b/app/javascript/flavours/glitch/features/notifications/components/notification.jsx index 211a319679..d03674bd57 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/notification.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/notification.jsx @@ -22,6 +22,7 @@ import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; import FollowRequestContainer from '../containers/follow_request_container'; import NotificationOverlayContainer from '../containers/overlay_container'; +import { ModerationWarning } from './moderation_warning'; import { RelationshipsSeveranceEvent } from './relationships_severance_event'; import Report from './report'; @@ -30,6 +31,7 @@ const messages = defineMessages({ adminSignUp: { id: 'notification.admin.sign_up', defaultMessage: '{name} signed up' }, adminReport: { id: 'notification.admin.report', defaultMessage: '{name} reported {target}' }, relationshipsSevered: { id: 'notification.relationships_severance_event', defaultMessage: 'Lost connections with {name}' }, + moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'Your have received a moderation warning' }, }); const notificationForScreenReader = (intl, message, timestamp) => { @@ -328,6 +330,27 @@ class Notification extends ImmutablePureComponent { ); } + renderModerationWarning (notification) { + const { intl, unread, hidden } = this.props; + const warning = notification.get('moderation_warning'); + + if (!warning) { + return null; + } + + return ( + +
+
+
+ ); + } + renderAdminSignUp (notification, account, link) { const { intl, unread } = this.props; @@ -423,6 +446,8 @@ class Notification extends ImmutablePureComponent { return this.renderPoll(notification); case 'severed_relationships': return this.renderRelationshipsSevered(notification); + case 'moderation_warning': + return this.renderModerationWarning(notification); case 'admin.sign_up': return this.renderAdminSignUp(notification, account, link); case 'admin.report': diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js index 6edf84b67a..c5f36dd94a 100644 --- a/app/javascript/flavours/glitch/reducers/notifications.js +++ b/app/javascript/flavours/glitch/reducers/notifications.js @@ -62,6 +62,7 @@ export const notificationToMap = (notification, markForDelete = false) => Immuta status: notification.status ? notification.status.id : null, report: notification.report ? fromJS(notification.report) : null, event: notification.event ? fromJS(notification.event) : null, + moderation_warning: notification.moderation_warning ? fromJS(notification.moderation_warning) : null, }); const normalizeNotification = (state, notification, usePendingItems) => { diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index a52f384657..96f0c81665 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -2394,7 +2394,8 @@ a.account__display-name { } } -.notification__relationships-severance-event { +.notification__relationships-severance-event, +.notification__moderation-warning { display: flex; gap: 16px; color: $secondary-text-color; From a4ce53df2721a4ec16bbc41001f8f1c430204490 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 26 Apr 2024 17:33:15 +0200 Subject: [PATCH 077/658] [Glitch] Change moderation warning notification icon Port de4a7bf53159f72a9a122bf8df21e8d5f4ad7512 to glitch-soc Signed-off-by: Claire --- .../features/notifications/components/moderation_warning.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/flavours/glitch/features/notifications/components/moderation_warning.tsx b/app/javascript/flavours/glitch/features/notifications/components/moderation_warning.tsx index 28c3aa1984..2fd19c5108 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/moderation_warning.tsx +++ b/app/javascript/flavours/glitch/features/notifications/components/moderation_warning.tsx @@ -1,6 +1,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import WarningIcon from '@/material-icons/400-24px/warning-fill.svg?react'; +import GavelIcon from '@/material-icons/400-24px/gavel.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; // This needs to be kept in sync with app/models/account_warning.rb @@ -62,7 +62,7 @@ export const ModerationWarning: React.FC = ({ action, id, hidden }) => { rel='noopener noreferrer' className='notification__moderation-warning' > - +

{intl.formatMessage(messages[action])}

From 552e09d57f195633e635b9d036b1c74fd1b2a643 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 26 Apr 2024 19:11:27 +0200 Subject: [PATCH 078/658] [Glitch] Fix marker thunks to not ignore eslint directives for the whole file Port 65093c619fdd1b18a4cf0c288051d8c524d5f434 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/actions/markers.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/javascript/flavours/glitch/actions/markers.ts b/app/javascript/flavours/glitch/actions/markers.ts index 78362a9ca3..8fc7d1fb40 100644 --- a/app/javascript/flavours/glitch/actions/markers.ts +++ b/app/javascript/flavours/glitch/actions/markers.ts @@ -3,7 +3,7 @@ import { List as ImmutableList } from 'immutable'; import { debounce } from 'lodash'; import type { MarkerJSON } from 'flavours/glitch/api_types/markers'; -import type { RootState } from 'flavours/glitch/store'; +import type { AppDispatch, RootState } from 'flavours/glitch/store'; import { createAppAsyncThunk } from 'flavours/glitch/store/typed_functions'; import api, { authorizationTokenFromState } from '../api'; @@ -72,18 +72,21 @@ interface MarkerParam { } function getLastHomeId(state: RootState): string | undefined { - /* eslint-disable @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return ( + // eslint-disable-next-line @typescript-eslint/no-unsafe-call state // @ts-expect-error state.timelines is not yet typed .getIn(['timelines', 'home', 'items'], ImmutableList()) // @ts-expect-error state.timelines is not yet typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access .find((item) => item !== null) ); } function getLastNotificationId(state: RootState): string | undefined { // @ts-expect-error state.notifications is not yet typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call return state.getIn(['notifications', 'lastReadId']); } @@ -132,8 +135,8 @@ export const submitMarkersAction = createAppAsyncThunk<{ }); const debouncedSubmitMarkers = debounce( - (dispatch) => { - dispatch(submitMarkersAction()); + (dispatch: AppDispatch) => { + void dispatch(submitMarkersAction()); }, 300000, { From defd1e4024ffb89b8dbcc82fb7384903cd2c3e79 Mon Sep 17 00:00:00 2001 From: David Beck Date: Mon, 29 Apr 2024 00:55:58 -0700 Subject: [PATCH 079/658] [Glitch] Remove home marker updates Port 4f4b77920eeb3ba65346862d489945494dfeab64 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/markers.ts | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/app/javascript/flavours/glitch/actions/markers.ts b/app/javascript/flavours/glitch/actions/markers.ts index 8fc7d1fb40..3f810cf99a 100644 --- a/app/javascript/flavours/glitch/actions/markers.ts +++ b/app/javascript/flavours/glitch/actions/markers.ts @@ -1,5 +1,3 @@ -import { List as ImmutableList } from 'immutable'; - import { debounce } from 'lodash'; import type { MarkerJSON } from 'flavours/glitch/api_types/markers'; @@ -71,19 +69,6 @@ interface MarkerParam { last_read_id?: string; } -function getLastHomeId(state: RootState): string | undefined { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return ( - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - state - // @ts-expect-error state.timelines is not yet typed - .getIn(['timelines', 'home', 'items'], ImmutableList()) - // @ts-expect-error state.timelines is not yet typed - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - .find((item) => item !== null) - ); -} - function getLastNotificationId(state: RootState): string | undefined { // @ts-expect-error state.notifications is not yet typed // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call @@ -93,15 +78,8 @@ function getLastNotificationId(state: RootState): string | undefined { const buildPostMarkersParams = (state: RootState) => { const params = {} as { home?: MarkerParam; notifications?: MarkerParam }; - const lastHomeId = getLastHomeId(state); const lastNotificationId = getLastNotificationId(state); - if (lastHomeId && compareId(lastHomeId, state.markers.home) > 0) { - params.home = { - last_read_id: lastHomeId, - }; - } - if ( lastNotificationId && lastNotificationId !== '0' && From fe7db7905fe9b8a120b6f6f7169eefd3df976727 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 29 Apr 2024 10:02:41 +0200 Subject: [PATCH 080/658] [Glitch] Convert easy entrypoints files to Typescript Port 36909065b544d06e8487f1e0679e595fd01a7f22 to glitch-soc Signed-off-by: Claire --- .../entrypoints/{application.js => application.ts} | 4 ++-- .../glitch/entrypoints/{error.js => error.ts} | 6 +++++- .../glitch/entrypoints/{inert.js => inert.ts} | 0 .../glitch/entrypoints/{mailer.js => mailer.ts} | 0 .../glitch/entrypoints/{share.jsx => share.tsx} | 14 +++++++++----- 5 files changed, 16 insertions(+), 8 deletions(-) rename app/javascript/flavours/glitch/entrypoints/{application.js => application.ts} (80%) rename app/javascript/flavours/glitch/entrypoints/{error.js => error.ts} (66%) rename app/javascript/flavours/glitch/entrypoints/{inert.js => inert.ts} (100%) rename app/javascript/flavours/glitch/entrypoints/{mailer.js => mailer.ts} (100%) rename app/javascript/flavours/glitch/entrypoints/{share.jsx => share.tsx} (74%) diff --git a/app/javascript/flavours/glitch/entrypoints/application.js b/app/javascript/flavours/glitch/entrypoints/application.ts similarity index 80% rename from app/javascript/flavours/glitch/entrypoints/application.js rename to app/javascript/flavours/glitch/entrypoints/application.ts index a0b5d714c4..3659d8212b 100644 --- a/app/javascript/flavours/glitch/entrypoints/application.js +++ b/app/javascript/flavours/glitch/entrypoints/application.ts @@ -2,7 +2,7 @@ import '@/entrypoints/public-path'; import { start } from 'flavours/glitch/common'; import { loadLocale } from 'flavours/glitch/locales'; -import main from "flavours/glitch/main"; +import main from 'flavours/glitch/main'; import { loadPolyfills } from 'flavours/glitch/polyfills'; start(); @@ -10,6 +10,6 @@ start(); loadPolyfills() .then(loadLocale) .then(main) - .catch(e => { + .catch((e: unknown) => { console.error(e); }); diff --git a/app/javascript/flavours/glitch/entrypoints/error.js b/app/javascript/flavours/glitch/entrypoints/error.ts similarity index 66% rename from app/javascript/flavours/glitch/entrypoints/error.js rename to app/javascript/flavours/glitch/entrypoints/error.ts index 4315d20de1..9e067d4caa 100644 --- a/app/javascript/flavours/glitch/entrypoints/error.js +++ b/app/javascript/flavours/glitch/entrypoints/error.ts @@ -2,7 +2,9 @@ import '@/entrypoints/public-path'; import ready from 'flavours/glitch/ready'; ready(() => { - const image = document.querySelector('img'); + const image = document.querySelector('img'); + + if (!image) return; image.addEventListener('mouseenter', () => { image.src = '/oops.gif'; @@ -11,4 +13,6 @@ ready(() => { image.addEventListener('mouseleave', () => { image.src = '/oops.png'; }); +}).catch((e: unknown) => { + console.error(e); }); diff --git a/app/javascript/flavours/glitch/entrypoints/inert.js b/app/javascript/flavours/glitch/entrypoints/inert.ts similarity index 100% rename from app/javascript/flavours/glitch/entrypoints/inert.js rename to app/javascript/flavours/glitch/entrypoints/inert.ts diff --git a/app/javascript/flavours/glitch/entrypoints/mailer.js b/app/javascript/flavours/glitch/entrypoints/mailer.ts similarity index 100% rename from app/javascript/flavours/glitch/entrypoints/mailer.js rename to app/javascript/flavours/glitch/entrypoints/mailer.ts diff --git a/app/javascript/flavours/glitch/entrypoints/share.jsx b/app/javascript/flavours/glitch/entrypoints/share.tsx similarity index 74% rename from app/javascript/flavours/glitch/entrypoints/share.jsx rename to app/javascript/flavours/glitch/entrypoints/share.tsx index 62d2f6df42..0eda442506 100644 --- a/app/javascript/flavours/glitch/entrypoints/share.jsx +++ b/app/javascript/flavours/glitch/entrypoints/share.tsx @@ -16,7 +16,7 @@ function loaded() { if (!attr) return; - const props = JSON.parse(attr); + const props = JSON.parse(attr) as object; const root = createRoot(mountNode); root.render(); @@ -24,9 +24,13 @@ function loaded() { } function main() { - ready(loaded); + ready(loaded).catch((error: unknown) => { + console.error(error); + }); } -loadPolyfills().then(main).catch(error => { - console.error(error); -}); +loadPolyfills() + .then(main) + .catch((error: unknown) => { + console.error(error); + }); From 494d28bb563caac94f8f4fda3683525b69a6f69f Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 29 Apr 2024 10:23:05 +0200 Subject: [PATCH 081/658] [Glitch] Convert `entrypoints/sign_up` to Typescript Port 4527e012daa61dc07258eaedf3e03179b59fca8d to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/entrypoints/sign_up.js | 42 ---------------- .../flavours/glitch/entrypoints/sign_up.ts | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 42 deletions(-) delete mode 100644 app/javascript/flavours/glitch/entrypoints/sign_up.js create mode 100644 app/javascript/flavours/glitch/entrypoints/sign_up.ts diff --git a/app/javascript/flavours/glitch/entrypoints/sign_up.js b/app/javascript/flavours/glitch/entrypoints/sign_up.js deleted file mode 100644 index ded1d4cbde..0000000000 --- a/app/javascript/flavours/glitch/entrypoints/sign_up.js +++ /dev/null @@ -1,42 +0,0 @@ -import '@/entrypoints/public-path'; -import axios from 'axios'; - -import ready from 'flavours/glitch/ready'; - -ready(() => { - setInterval(() => { - axios.get('/api/v1/emails/check_confirmation').then((response) => { - if (response.data) { - window.location = '/start'; - } - }).catch(error => { - console.error(error); - }); - }, 5000); - - document.querySelectorAll('.timer-button').forEach(button => { - let counter = 30; - - const container = document.createElement('span'); - - const updateCounter = () => { - container.innerText = ` (${counter})`; - }; - - updateCounter(); - - const countdown = setInterval(() => { - counter--; - - if (counter === 0) { - button.disabled = false; - button.removeChild(container); - clearInterval(countdown); - } else { - updateCounter(); - } - }, 1000); - - button.appendChild(container); - }); -}); diff --git a/app/javascript/flavours/glitch/entrypoints/sign_up.ts b/app/javascript/flavours/glitch/entrypoints/sign_up.ts new file mode 100644 index 0000000000..18e2931546 --- /dev/null +++ b/app/javascript/flavours/glitch/entrypoints/sign_up.ts @@ -0,0 +1,48 @@ +import '@/entrypoints/public-path'; +import axios from 'axios'; + +import ready from 'flavours/glitch/ready'; + +async function checkConfirmation() { + const response = await axios.get('/api/v1/emails/check_confirmation'); + + if (response.data) { + window.location.href = '/start'; + } +} + +ready(() => { + setInterval(() => { + void checkConfirmation(); + }, 5000); + + document + .querySelectorAll('button.timer-button') + .forEach((button) => { + let counter = 30; + + const container = document.createElement('span'); + + const updateCounter = () => { + container.innerText = ` (${counter})`; + }; + + updateCounter(); + + const countdown = setInterval(() => { + counter--; + + if (counter === 0) { + button.disabled = false; + button.removeChild(container); + clearInterval(countdown); + } else { + updateCounter(); + } + }, 1000); + + button.appendChild(container); + }); +}).catch((e: unknown) => { + throw e; +}); From e62595c9667151ec5038da9232639c97250f9c64 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 29 Apr 2024 11:29:59 +0200 Subject: [PATCH 082/658] [Glitch] Remove usage of deprecated `defaultTypes` on React functional components Port b9b4db483cc588a2eb334b63fe6740c8dad9b57b to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/components/badge.jsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/javascript/flavours/glitch/components/badge.jsx b/app/javascript/flavours/glitch/components/badge.jsx index 5e0b2587bd..2a335d7f50 100644 --- a/app/javascript/flavours/glitch/components/badge.jsx +++ b/app/javascript/flavours/glitch/components/badge.jsx @@ -7,7 +7,7 @@ import PersonIcon from '@/material-icons/400-24px/person.svg?react'; import SmartToyIcon from '@/material-icons/400-24px/smart_toy.svg?react'; -export const Badge = ({ icon, label, domain, roleId }) => ( +export const Badge = ({ icon = , label, domain, roleId }) => (
{icon} {label} @@ -22,10 +22,6 @@ Badge.propTypes = { roleId: PropTypes.string }; -Badge.defaultProps = { - icon: , -}; - export const GroupBadge = () => ( } label={} /> ); From 6662d604c161716856ca5a7f55d78d4a63207040 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 29 Apr 2024 11:55:41 +0200 Subject: [PATCH 083/658] [Glitch] Add loading indicator and empty result message to advanced interface search Port 7d3fe2b4c3cd9511df8f8026890c71b2119719f3 to glitch-soc Signed-off-by: Claire --- .../compose/components/search_results.jsx | 112 +++++++++--------- .../containers/search_results_container.js | 20 ---- .../glitch/features/compose/index.jsx | 4 +- .../flavours/glitch/reducers/search.js | 1 + 4 files changed, 62 insertions(+), 75 deletions(-) delete mode 100644 app/javascript/flavours/glitch/features/compose/containers/search_results_container.js diff --git a/app/javascript/flavours/glitch/features/compose/components/search_results.jsx b/app/javascript/flavours/glitch/features/compose/components/search_results.jsx index 3df025db55..350fc41c51 100644 --- a/app/javascript/flavours/glitch/features/compose/components/search_results.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/search_results.jsx @@ -1,16 +1,16 @@ -import PropTypes from 'prop-types'; +import { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; - import FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react'; import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; import TagIcon from '@/material-icons/400-24px/tag.svg?react'; +import { expandSearch } from 'flavours/glitch/actions/search'; import { Icon } from 'flavours/glitch/components/icon'; import { LoadMore } from 'flavours/glitch/components/load_more'; +import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import { SearchSection } from 'flavours/glitch/features/explore/components/search_section'; +import { useAppDispatch, useAppSelector } from 'flavours/glitch/store'; import { ImmutableHashtag as Hashtag } from '../../../components/hashtag'; import AccountContainer from '../../../containers/account_container'; @@ -26,62 +26,68 @@ const withoutLastResult = list => { } }; -class SearchResults extends ImmutablePureComponent { +export const SearchResults = () => { + const results = useAppSelector((state) => state.getIn(['search', 'results'])); + const isLoading = useAppSelector((state) => state.getIn(['search', 'isLoading'])); - static propTypes = { - results: ImmutablePropTypes.map.isRequired, - expandSearch: PropTypes.func.isRequired, - searchTerm: PropTypes.string, - }; + const dispatch = useAppDispatch(); - handleLoadMoreAccounts = () => this.props.expandSearch('accounts'); + const handleLoadMoreAccounts = useCallback(() => { + dispatch(expandSearch('accounts')); + }, [dispatch]); - handleLoadMoreStatuses = () => this.props.expandSearch('statuses'); + const handleLoadMoreStatuses = useCallback(() => { + dispatch(expandSearch('statuses')); + }, [dispatch]); - handleLoadMoreHashtags = () => this.props.expandSearch('hashtags'); + const handleLoadMoreHashtags = useCallback(() => { + dispatch(expandSearch('hashtags')); + }, [dispatch]); - render () { - const { results } = this.props; + let accounts, statuses, hashtags; - let accounts, statuses, hashtags; - - if (results.get('accounts') && results.get('accounts').size > 0) { - accounts = ( - }> - {withoutLastResult(results.get('accounts')).map(accountId => )} - {(results.get('accounts').size > INITIAL_PAGE_LIMIT && results.get('accounts').size % INITIAL_PAGE_LIMIT === 1) && } - - ); - } - - if (results.get('hashtags') && results.get('hashtags').size > 0) { - hashtags = ( - }> - {withoutLastResult(results.get('hashtags')).map(hashtag => )} - {(results.get('hashtags').size > INITIAL_PAGE_LIMIT && results.get('hashtags').size % INITIAL_PAGE_LIMIT === 1) && } - - ); - } - - if (results.get('statuses') && results.get('statuses').size > 0) { - statuses = ( - }> - {withoutLastResult(results.get('statuses')).map(statusId => )} - {(results.get('statuses').size > INITIAL_PAGE_LIMIT && results.get('statuses').size % INITIAL_PAGE_LIMIT === 1) && } - - ); - } - - - return ( -
- {accounts} - {hashtags} - {statuses} -
+ if (results.get('accounts') && results.get('accounts').size > 0) { + accounts = ( + }> + {withoutLastResult(results.get('accounts')).map(accountId => )} + {(results.get('accounts').size > INITIAL_PAGE_LIMIT && results.get('accounts').size % INITIAL_PAGE_LIMIT === 1) && } + ); } -} + if (results.get('hashtags') && results.get('hashtags').size > 0) { + hashtags = ( + }> + {withoutLastResult(results.get('hashtags')).map(hashtag => )} + {(results.get('hashtags').size > INITIAL_PAGE_LIMIT && results.get('hashtags').size % INITIAL_PAGE_LIMIT === 1) && } + + ); + } -export default SearchResults; + if (results.get('statuses') && results.get('statuses').size > 0) { + statuses = ( + }> + {withoutLastResult(results.get('statuses')).map(statusId => )} + {(results.get('statuses').size > INITIAL_PAGE_LIMIT && results.get('statuses').size % INITIAL_PAGE_LIMIT === 1) && } + + ); + } + + return ( +
+ {!accounts && !hashtags && !statuses && ( + isLoading ? ( + + ) : ( +
+ +
+ ) + )} + {accounts} + {hashtags} + {statuses} +
+ ); + +}; diff --git a/app/javascript/flavours/glitch/features/compose/containers/search_results_container.js b/app/javascript/flavours/glitch/features/compose/containers/search_results_container.js deleted file mode 100644 index 7287a022b4..0000000000 --- a/app/javascript/flavours/glitch/features/compose/containers/search_results_container.js +++ /dev/null @@ -1,20 +0,0 @@ -import { connect } from 'react-redux'; - -import { expandSearch } from 'flavours/glitch/actions/search'; -import { fetchSuggestions, dismissSuggestion } from 'flavours/glitch/actions/suggestions'; - -import SearchResults from '../components/search_results'; - -const mapStateToProps = state => ({ - results: state.getIn(['search', 'results']), - suggestions: state.getIn(['suggestions', 'items']), - searchTerm: state.getIn(['search', 'searchTerm']), -}); - -const mapDispatchToProps = dispatch => ({ - fetchSuggestions: () => dispatch(fetchSuggestions()), - expandSearch: type => dispatch(expandSearch(type)), - dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))), -}); - -export default connect(mapStateToProps, mapDispatchToProps)(SearchResults); diff --git a/app/javascript/flavours/glitch/features/compose/index.jsx b/app/javascript/flavours/glitch/features/compose/index.jsx index 0bba28b787..b59fafe048 100644 --- a/app/javascript/flavours/glitch/features/compose/index.jsx +++ b/app/javascript/flavours/glitch/features/compose/index.jsx @@ -32,9 +32,9 @@ import { mascot } from '../../initial_state'; import { isMobile } from '../../is_mobile'; import Motion from '../ui/util/optional_motion'; +import { SearchResults } from './components/search_results'; import ComposeFormContainer from './containers/compose_form_container'; import SearchContainer from './containers/search_container'; -import SearchResultsContainer from './containers/search_results_container'; const messages = defineMessages({ start: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, @@ -183,7 +183,7 @@ class Compose extends PureComponent { {({ x }) => (
- +
)}
diff --git a/app/javascript/flavours/glitch/reducers/search.js b/app/javascript/flavours/glitch/reducers/search.js index 72835eb917..7828d49eee 100644 --- a/app/javascript/flavours/glitch/reducers/search.js +++ b/app/javascript/flavours/glitch/reducers/search.js @@ -50,6 +50,7 @@ export default function search(state = initialState, action) { return state.set('hidden', true); case SEARCH_FETCH_REQUEST: return state.withMutations(map => { + map.set('results', ImmutableMap()); map.set('isLoading', true); map.set('submitted', true); map.set('type', action.searchType); From 4b82dc84f520f459063c2a7c9ad59653a2a95181 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 1 May 2024 01:39:28 +0200 Subject: [PATCH 084/658] [Glitch] Change width breakpoint for mobile placement behavior Port 26e10aa203d18e452cdf836209875f05a6e01882 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/styles/components.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 96f0c81665..2fcee38eb4 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -6114,7 +6114,7 @@ a.status-card { user-select: text; display: flex; - @media screen and (max-width: $no-gap-breakpoint) { + @media screen and (width <= 630px) { margin-top: auto; } } From b6ada33ad4d98015df27878352955a4d5bc7d630 Mon Sep 17 00:00:00 2001 From: mogaminsk Date: Thu, 2 May 2024 18:40:18 +0900 Subject: [PATCH 085/658] [Glitch] Fix word breaking in filtered notifications badge Port 616e2f26668d578ae81043a3836e881178d3e806 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/styles/components.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 2fcee38eb4..f5518907ce 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -10733,6 +10733,7 @@ noscript { font-weight: 500; font-size: 11px; line-height: 16px; + word-break: keep-all; &__badge { background: $ui-button-background-color; From c59f6ef5b8789f9b7879ef5d3491231f3a36cb4a Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 2 May 2024 14:02:13 +0200 Subject: [PATCH 086/658] [Glitch] Convert `entrypoints/two_factor_authentication` to Typescript Port 9e260014c72fa83740d70d2d603e836f86e64b55 to glitch-soc Signed-off-by: Claire --- .../entrypoints/two_factor_authentication.js | 119 ----------- .../entrypoints/two_factor_authentication.ts | 197 ++++++++++++++++++ 2 files changed, 197 insertions(+), 119 deletions(-) delete mode 100644 app/javascript/flavours/glitch/entrypoints/two_factor_authentication.js create mode 100644 app/javascript/flavours/glitch/entrypoints/two_factor_authentication.ts diff --git a/app/javascript/flavours/glitch/entrypoints/two_factor_authentication.js b/app/javascript/flavours/glitch/entrypoints/two_factor_authentication.js deleted file mode 100644 index 8b606fcc7a..0000000000 --- a/app/javascript/flavours/glitch/entrypoints/two_factor_authentication.js +++ /dev/null @@ -1,119 +0,0 @@ -import * as WebAuthnJSON from '@github/webauthn-json'; -import axios from 'axios'; - -import ready from 'flavours/glitch/ready'; -import 'regenerator-runtime/runtime'; - -function getCSRFToken() { - var CSRFSelector = document.querySelector('meta[name="csrf-token"]'); - if (CSRFSelector) { - return CSRFSelector.getAttribute('content'); - } else { - return null; - } -} - -function hideFlashMessages() { - Array.from(document.getElementsByClassName('flash-message')).forEach(function(flashMessage) { - flashMessage.classList.add('hidden'); - }); -} - -function callback(url, body) { - axios.post(url, JSON.stringify(body), { - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'X-CSRF-Token': getCSRFToken(), - }, - credentials: 'same-origin', - }).then(function(response) { - window.location.replace(response.data.redirect_path); - }).catch(function(error) { - if (error.response.status === 422) { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error.response.data.error); - } else { - console.error(error); - } - }); -} - -ready(() => { - if (!WebAuthnJSON.supported()) { - const unsupported_browser_message = document.getElementById('unsupported-browser-message'); - if (unsupported_browser_message) { - unsupported_browser_message.classList.remove('hidden'); - document.querySelector('.btn.js-webauthn').disabled = true; - } - } - - - const webAuthnCredentialRegistrationForm = document.getElementById('new_webauthn_credential'); - if (webAuthnCredentialRegistrationForm) { - webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => { - event.preventDefault(); - - var nickname = event.target.querySelector('input[name="new_webauthn_credential[nickname]"]'); - if (nickname.value) { - axios.get('/settings/security_keys/options') - .then((response) => { - const credentialOptions = response.data; - - WebAuthnJSON.create({ 'publicKey': credentialOptions }).then((credential) => { - var params = { 'credential': credential, 'nickname': nickname.value }; - callback('/settings/security_keys', params); - }).catch((error) => { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error); - }); - }).catch((error) => { - console.error(error.response.data.error); - }); - } else { - nickname.focus(); - } - }); - } - - const webAuthnCredentialAuthenticationForm = document.getElementById('webauthn-form'); - if (webAuthnCredentialAuthenticationForm) { - webAuthnCredentialAuthenticationForm.addEventListener('submit', (event) => { - event.preventDefault(); - - axios.get('sessions/security_key_options') - .then((response) => { - const credentialOptions = response.data; - - WebAuthnJSON.get({ 'publicKey': credentialOptions }).then((credential) => { - var params = { 'user': { 'credential': credential } }; - callback('sign_in', params); - }).catch((error) => { - const errorMessage = document.getElementById('security-key-error-message'); - errorMessage.classList.remove('hidden'); - console.error(error); - }); - }).catch((error) => { - console.error(error.response.data.error); - }); - }); - - const otpAuthenticationForm = document.getElementById('otp-authentication-form'); - - const linkToOtp = document.getElementById('link-to-otp'); - linkToOtp.addEventListener('click', () => { - webAuthnCredentialAuthenticationForm.classList.add('hidden'); - otpAuthenticationForm.classList.remove('hidden'); - hideFlashMessages(); - }); - - const linkToWebAuthn = document.getElementById('link-to-webauthn'); - linkToWebAuthn.addEventListener('click', () => { - otpAuthenticationForm.classList.add('hidden'); - webAuthnCredentialAuthenticationForm.classList.remove('hidden'); - hideFlashMessages(); - }); - } -}); diff --git a/app/javascript/flavours/glitch/entrypoints/two_factor_authentication.ts b/app/javascript/flavours/glitch/entrypoints/two_factor_authentication.ts new file mode 100644 index 0000000000..3106167117 --- /dev/null +++ b/app/javascript/flavours/glitch/entrypoints/two_factor_authentication.ts @@ -0,0 +1,197 @@ +import * as WebAuthnJSON from '@github/webauthn-json'; +import axios, { AxiosError } from 'axios'; + +import ready from 'flavours/glitch/ready'; + +import 'regenerator-runtime/runtime'; + +type PublicKeyCredentialCreationOptionsJSON = + WebAuthnJSON.CredentialCreationOptionsJSON['publicKey']; + +function exceptionHasAxiosError( + error: unknown, +): error is AxiosError<{ error: unknown }> { + return ( + error instanceof AxiosError && + typeof error.response?.data === 'object' && + 'error' in error.response.data + ); +} + +function logAxiosResponseError(error: unknown) { + if (exceptionHasAxiosError(error)) console.error(error); +} + +function getCSRFToken() { + return document + .querySelector('meta[name="csrf-token"]') + ?.getAttribute('content'); +} + +function hideFlashMessages() { + document.querySelectorAll('.flash-message').forEach((flashMessage) => { + flashMessage.classList.add('hidden'); + }); +} + +async function callback( + url: string, + body: + | { + credential: WebAuthnJSON.PublicKeyCredentialWithAttestationJSON; + nickname: string; + } + | { + user: { credential: WebAuthnJSON.PublicKeyCredentialWithAssertionJSON }; + }, +) { + try { + const response = await axios.post<{ redirect_path: string }>( + url, + JSON.stringify(body), + { + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + 'X-CSRF-Token': getCSRFToken(), + }, + }, + ); + + window.location.replace(response.data.redirect_path); + } catch (error) { + if (error instanceof AxiosError && error.response?.status === 422) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + + logAxiosResponseError(error); + } else { + console.error(error); + } + } +} + +async function handleWebauthnCredentialRegistration(nickname: string) { + try { + const response = await axios.get( + '/settings/security_keys/options', + ); + + const credentialOptions = response.data; + + try { + const credential = await WebAuthnJSON.create({ + publicKey: credentialOptions, + }); + + const params = { + credential: credential, + nickname: nickname, + }; + + await callback('/settings/security_keys', params); + } catch (error) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + console.error(error); + } + } catch (error) { + logAxiosResponseError(error); + } +} + +async function handleWebauthnCredentialAuthentication() { + try { + const response = await axios.get( + 'sessions/security_key_options', + ); + + const credentialOptions = response.data; + + try { + const credential = await WebAuthnJSON.get({ + publicKey: credentialOptions, + }); + + const params = { user: { credential: credential } }; + void callback('sign_in', params); + } catch (error) { + const errorMessage = document.getElementById( + 'security-key-error-message', + ); + errorMessage?.classList.remove('hidden'); + console.error(error); + } + } catch (error) { + logAxiosResponseError(error); + } +} + +ready(() => { + if (!WebAuthnJSON.supported()) { + const unsupported_browser_message = document.getElementById( + 'unsupported-browser-message', + ); + if (unsupported_browser_message) { + unsupported_browser_message.classList.remove('hidden'); + const button = document.querySelector( + 'button.btn.js-webauthn', + ); + if (button) button.disabled = true; + } + } + + const webAuthnCredentialRegistrationForm = + document.querySelector('form#new_webauthn_credential'); + if (webAuthnCredentialRegistrationForm) { + webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => { + event.preventDefault(); + + if (!(event.target instanceof HTMLFormElement)) return; + + const nickname = event.target.querySelector( + 'input[name="new_webauthn_credential[nickname]"]', + ); + + if (nickname?.value) { + void handleWebauthnCredentialRegistration(nickname.value); + } else { + nickname?.focus(); + } + }); + } + + const webAuthnCredentialAuthenticationForm = + document.getElementById('webauthn-form'); + if (webAuthnCredentialAuthenticationForm) { + webAuthnCredentialAuthenticationForm.addEventListener('submit', (event) => { + event.preventDefault(); + void handleWebauthnCredentialAuthentication(); + }); + + const otpAuthenticationForm = document.getElementById( + 'otp-authentication-form', + ); + + const linkToOtp = document.getElementById('link-to-otp'); + + linkToOtp?.addEventListener('click', () => { + webAuthnCredentialAuthenticationForm.classList.add('hidden'); + otpAuthenticationForm?.classList.remove('hidden'); + hideFlashMessages(); + }); + + const linkToWebAuthn = document.getElementById('link-to-webauthn'); + linkToWebAuthn?.addEventListener('click', () => { + otpAuthenticationForm?.classList.add('hidden'); + webAuthnCredentialAuthenticationForm.classList.remove('hidden'); + hideFlashMessages(); + }); + } +}).catch((e: unknown) => { + throw e; +}); From 2f73e486b7e107763e92b47b8659e152f363d988 Mon Sep 17 00:00:00 2001 From: Tim Rogers Date: Sat, 4 May 2024 21:24:10 -0500 Subject: [PATCH 087/658] =?UTF-8?q?Switched=20HTMLEntities=20to=20the=20ex?= =?UTF-8?q?panded=20flavor=20which=20supports=20a=20larger=20=E2=80=A6=20(?= =?UTF-8?q?#30173)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/link_details_extractor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/link_details_extractor.rb b/app/lib/link_details_extractor.rb index bec7d3a455..07776c3699 100644 --- a/app/lib/link_details_extractor.rb +++ b/app/lib/link_details_extractor.rb @@ -282,6 +282,6 @@ class LinkDetailsExtractor end def html_entities - @html_entities ||= HTMLEntities.new + @html_entities ||= HTMLEntities.new(:expanded) end end From e4841ca82b58f33ec42742b40211f38fef1e7338 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 10:26:12 +0200 Subject: [PATCH 088/658] Update dependency irb to v1.13.1 (#30177) 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 cb36bc2ddc..27d858ed05 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -346,7 +346,7 @@ GEM activesupport (>= 3.0) nokogiri (>= 1.6) io-console (0.7.2) - irb (1.13.0) + irb (1.13.1) rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) @@ -601,7 +601,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.9.0) - reline (0.5.4) + reline (0.5.5) io-console (~> 0.5) request_store (1.6.0) rack (>= 1.4) From d544b83f917773749f9664be4bca4eec4078a2b6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 10:26:28 +0200 Subject: [PATCH 089/658] Update formatjs monorepo (#30175) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index e45da3a480..7f0747faa1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2307,23 +2307,23 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl@npm:2.10.1": - version: 2.10.1 - resolution: "@formatjs/intl@npm:2.10.1" +"@formatjs/intl@npm:2.10.2": + version: 2.10.2 + resolution: "@formatjs/intl@npm:2.10.2" dependencies: "@formatjs/ecma402-abstract": "npm:1.18.2" "@formatjs/fast-memoize": "npm:2.2.0" "@formatjs/icu-messageformat-parser": "npm:2.7.6" "@formatjs/intl-displaynames": "npm:6.6.6" "@formatjs/intl-listformat": "npm:7.5.5" - intl-messageformat: "npm:10.5.11" + intl-messageformat: "npm:10.5.12" tslib: "npm:^2.4.0" peerDependencies: typescript: ^4.7 || 5 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/24eee77382d1efd226aee7590228d3ae80f66a8547a65295f8028986b15b6abbfea3e380f4a338ece0e841e1db6f36554ca48124d84c0830382e3a9d395b5d75 + checksum: 10c0/20df407e141055e8c7b2605c06e952b643be7ea01d992862e13fc623ca2db034069744eae2be16655bf7888b3add1bfc2653fd0a08bcfdb67fb9b72a306f7718 languageName: node linkType: hard @@ -9615,15 +9615,15 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.5.11, intl-messageformat@npm:^10.3.5": - version: 10.5.11 - resolution: "intl-messageformat@npm:10.5.11" +"intl-messageformat@npm:10.5.12, intl-messageformat@npm:^10.3.5": + version: 10.5.12 + resolution: "intl-messageformat@npm:10.5.12" dependencies: "@formatjs/ecma402-abstract": "npm:1.18.2" "@formatjs/fast-memoize": "npm:2.2.0" "@formatjs/icu-messageformat-parser": "npm:2.7.6" tslib: "npm:^2.4.0" - checksum: 10c0/423f1c879ce2d0e7b9e0b4c1787a81ead7fe4d1734e0366a20fef56b06c09146e7ca3618e2e78b4f8b8f2b59cafe6237ceed21530fe0c16cfb47d915fc80222d + checksum: 10c0/f95734e98a05ef7f51de0c27904d3a994528e3a174963bd1b3a6db9416b5fd84bbd8f7d26d84fc547d51af69ccf46dd3f73a3f4f20a2ccef5c9cd90e946ad82c languageName: node linkType: hard @@ -14346,18 +14346,18 @@ __metadata: linkType: hard "react-intl@npm:^6.4.2": - version: 6.6.5 - resolution: "react-intl@npm:6.6.5" + version: 6.6.6 + resolution: "react-intl@npm:6.6.6" dependencies: "@formatjs/ecma402-abstract": "npm:1.18.2" "@formatjs/icu-messageformat-parser": "npm:2.7.6" - "@formatjs/intl": "npm:2.10.1" + "@formatjs/intl": "npm:2.10.2" "@formatjs/intl-displaynames": "npm:6.6.6" "@formatjs/intl-listformat": "npm:7.5.5" "@types/hoist-non-react-statics": "npm:^3.3.1" "@types/react": "npm:16 || 17 || 18" hoist-non-react-statics: "npm:^3.3.2" - intl-messageformat: "npm:10.5.11" + intl-messageformat: "npm:10.5.12" tslib: "npm:^2.4.0" peerDependencies: react: ^16.6.0 || 17 || 18 @@ -14365,7 +14365,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/31f231701af080bc923fdf25ff22ae7ad56bd7892602879fe6fa3de0c6ab95aab10ff86595372be155e0be45a7130a2cca91dbab73e558359cebc1785711ded2 + checksum: 10c0/04c1d1ca783f2a5e605544290c93e57629500be6811d7c2c3342903bf9f9a720d2e4c9cf3924133bf84e510ee879bf3d870a3ff269f5b197f894a49047bd089d languageName: node linkType: hard From a96b82802380f2220d7e2a059ca3c773c9ce3472 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 10:26:33 +0200 Subject: [PATCH 090/658] Update dependency postcss-preset-env to v9.5.11 (#30171) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 376 +++++++++++++++++++++++++++--------------------------- 1 file changed, 188 insertions(+), 188 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7f0747faa1..ddc789b5fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1551,13 +1551,13 @@ __metadata: languageName: node linkType: hard -"@csstools/cascade-layer-name-parser@npm:^1.0.9": - version: 1.0.9 - resolution: "@csstools/cascade-layer-name-parser@npm:1.0.9" +"@csstools/cascade-layer-name-parser@npm:^1.0.11": + version: 1.0.11 + resolution: "@csstools/cascade-layer-name-parser@npm:1.0.11" peerDependencies: - "@csstools/css-parser-algorithms": ^2.6.1 - "@csstools/css-tokenizer": ^2.2.4 - checksum: 10c0/f6e28c7cdeca44711288400cf20de9ebc4db71eafa39ca9a6b3e9f5d3295ba636dd986aac9fcb9e6171c84d436712d68ced923504d78d5fda0601c880eb352fe + "@csstools/css-parser-algorithms": ^2.6.3 + "@csstools/css-tokenizer": ^2.3.1 + checksum: 10c0/52ac8369877c8072ff5c111f656bd87e9a2a4b9e44e48fe005c26faeb6cffd83bfe2f463f4f385a2ae5cfe1f82bbf95d26ddaabca18b66c6b657c4fe1520fb43 languageName: node linkType: hard @@ -1568,52 +1568,52 @@ __metadata: languageName: node linkType: hard -"@csstools/css-calc@npm:^1.2.0": - version: 1.2.0 - resolution: "@csstools/css-calc@npm:1.2.0" +"@csstools/css-calc@npm:^1.2.2": + version: 1.2.2 + resolution: "@csstools/css-calc@npm:1.2.2" peerDependencies: - "@csstools/css-parser-algorithms": ^2.6.1 - "@csstools/css-tokenizer": ^2.2.4 - checksum: 10c0/ef12dc08ccdb9903e5cb24d81b469080b94c79123415f62f707196a85c53420b7729be608930314c7a9404f50c832fe5256f647c0567d1c825079cb77f6a8719 + "@csstools/css-parser-algorithms": ^2.6.3 + "@csstools/css-tokenizer": ^2.3.1 + checksum: 10c0/6032b482764a11c1b882d7502928950ab11760044fa7a2c23ecee802002902f6ea8fca045ee2919302af5a5c399e7baa9f68dff001ac6246ac7fef48fb3f6df7 languageName: node linkType: hard -"@csstools/css-color-parser@npm:^2.0.0": - version: 2.0.0 - resolution: "@csstools/css-color-parser@npm:2.0.0" +"@csstools/css-color-parser@npm:^2.0.2": + version: 2.0.2 + resolution: "@csstools/css-color-parser@npm:2.0.2" dependencies: "@csstools/color-helpers": "npm:^4.2.0" - "@csstools/css-calc": "npm:^1.2.0" + "@csstools/css-calc": "npm:^1.2.2" peerDependencies: - "@csstools/css-parser-algorithms": ^2.6.1 - "@csstools/css-tokenizer": ^2.2.4 - checksum: 10c0/295f844a194dec4f51439e8760dbb4a142901b8b60cd9d676a62c15c0e8408eb7bcdcbb40be52cdd5f67d020e655a1c3267a28923cfc4f6bae2b74aa48fce426 + "@csstools/css-parser-algorithms": ^2.6.3 + "@csstools/css-tokenizer": ^2.3.1 + checksum: 10c0/c5ae4ad78745e425dce56da9f1ab053fb4f7963399735df3303305b32123bed0b2237689c2e7e99da2c62387e3226c12ea85e70e275c4027c7507e4ac929bffa languageName: node linkType: hard -"@csstools/css-parser-algorithms@npm:^2.6.1": - version: 2.6.1 - resolution: "@csstools/css-parser-algorithms@npm:2.6.1" +"@csstools/css-parser-algorithms@npm:^2.6.1, @csstools/css-parser-algorithms@npm:^2.6.3": + version: 2.6.3 + resolution: "@csstools/css-parser-algorithms@npm:2.6.3" peerDependencies: - "@csstools/css-tokenizer": ^2.2.4 - checksum: 10c0/2c60377c4ffc96bbeb962cab19c09fccbcc834785928747219ed3bd916a34e52977393935d1d36501403f3f95ff59d358dd741d1dddcdaf9564ab36d73926aa6 + "@csstools/css-tokenizer": ^2.3.1 + checksum: 10c0/6648fda75a1c08096320fb5c04fd13656a0168de13584d2795547fecfb26c2c7d8b3b1fb79ba7aa758714851e98bfbec20d89e28697f999f41f91133eafe4207 languageName: node linkType: hard -"@csstools/css-tokenizer@npm:^2.2.4": - version: 2.2.4 - resolution: "@csstools/css-tokenizer@npm:2.2.4" - checksum: 10c0/23997db5874514f4b951ebd215e1e6cc8baf03adf9a35fc6fd028b84cb52aa2dc053860722108c09859a9b37b455f62b84181fe15539cd37797ea699b9ff85f0 +"@csstools/css-tokenizer@npm:^2.2.4, @csstools/css-tokenizer@npm:^2.3.1": + version: 2.3.1 + resolution: "@csstools/css-tokenizer@npm:2.3.1" + checksum: 10c0/fed6619fb5108e109d4dd10b0e967035a92793bae8fb84544e1342058b6df4e306d9d075623e2201fe88831b1ada797aea3546a8d12229d2d81cd7a5dfee4444 languageName: node linkType: hard -"@csstools/media-query-list-parser@npm:^2.1.9": - version: 2.1.9 - resolution: "@csstools/media-query-list-parser@npm:2.1.9" +"@csstools/media-query-list-parser@npm:^2.1.11, @csstools/media-query-list-parser@npm:^2.1.9": + version: 2.1.11 + resolution: "@csstools/media-query-list-parser@npm:2.1.11" peerDependencies: - "@csstools/css-parser-algorithms": ^2.6.1 - "@csstools/css-tokenizer": ^2.2.4 - checksum: 10c0/602e9b5631928c078e670018df20b959bfb8e42ea11024d5218f1604e5ef94e070a74934a919ccbff3713e506d99096057947fa0c2e4768939f7b22479553534 + "@csstools/css-parser-algorithms": ^2.6.3 + "@csstools/css-tokenizer": ^2.3.1 + checksum: 10c0/9bcd99f7d28ae3cdaba73fbbfef571b0393dd4e841f522cc796fe5161744f17e327ba1713dad3c481626fade1357c55890e3d365177abed50e857b69130a9be5 languageName: node linkType: hard @@ -1629,46 +1629,46 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-color-function@npm:^3.0.14": - version: 3.0.14 - resolution: "@csstools/postcss-color-function@npm:3.0.14" +"@csstools/postcss-color-function@npm:^3.0.16": + version: 3.0.16 + resolution: "@csstools/postcss-color-function@npm:3.0.16" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/81592b0eb3ad7022313ecafd028908b167de42acc6765f708c9b10631f86123c2b803aca27378f021c2b3dab8cc47770c0364fe5a3c1e18ec006deaf72e17c38 + checksum: 10c0/41756a4601a3f1086290dab6ca92b54e201bd94637b54b439c66a04fd628a14e2a0bd1452ad294d2981e2f4bb306758fa5f44639b1c4332320435050749aa487 languageName: node linkType: hard -"@csstools/postcss-color-mix-function@npm:^2.0.14": - version: 2.0.14 - resolution: "@csstools/postcss-color-mix-function@npm:2.0.14" +"@csstools/postcss-color-mix-function@npm:^2.0.16": + version: 2.0.16 + resolution: "@csstools/postcss-color-mix-function@npm:2.0.16" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/1dd3c63bbbbb9d3094699f169bbb9d26e86a49accb5f9abaa2441b54cb8a6f4cd332409666684a275eca867e3ef0ea3f6eafdf9fb87f2cbfa17c6296fb1ed4d7 + checksum: 10c0/70cd5b291dd615e20e4475517bf0027c90c433241397a66866f89acedb12cb91f45552a162bdd1000636ec56f7d6a099b65e44fe100fd03228fc65f17cfae285 languageName: node linkType: hard -"@csstools/postcss-exponential-functions@npm:^1.0.5": - version: 1.0.5 - resolution: "@csstools/postcss-exponential-functions@npm:1.0.5" +"@csstools/postcss-exponential-functions@npm:^1.0.7": + version: 1.0.7 + resolution: "@csstools/postcss-exponential-functions@npm:1.0.7" dependencies: - "@csstools/css-calc": "npm:^1.2.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-calc": "npm:^1.2.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" peerDependencies: postcss: ^8.4 - checksum: 10c0/45e18ca9025597da29cbef214cef39fcabef1e169bbb1f5c015de5f677e2927a1c3b8ae18558d815701e8d3e64db1043412a222af35036c92c25011a0e1e027d + checksum: 10c0/2079c81c3437686ef432d88502fa3a13bf8a27b7af105b4c6c2eb8e779f14adc8967a5a3ed03271ab919eeaf999fc4489fe4b37d32a8f61ab3212439517bddcc languageName: node linkType: hard @@ -1684,46 +1684,46 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-gamut-mapping@npm:^1.0.7": - version: 1.0.7 - resolution: "@csstools/postcss-gamut-mapping@npm:1.0.7" +"@csstools/postcss-gamut-mapping@npm:^1.0.9": + version: 1.0.9 + resolution: "@csstools/postcss-gamut-mapping@npm:1.0.9" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" peerDependencies: postcss: ^8.4 - checksum: 10c0/7b349db44fcd697d57172ab63b7a02a56c0b49bce17e48cb72aa0fa246bd2be83fe693c507fd400a9ed83597a711d18ece9319ee3af8000c8fd3a2761e228a11 + checksum: 10c0/412ae1410f3fce240401576441637c2c4e71d1a54153ac9b7a991b3de7519c253d03e10db78b09872eb10b0776d7f960b442779efabc11332b5be6672163c836 languageName: node linkType: hard -"@csstools/postcss-gradients-interpolation-method@npm:^4.0.15": - version: 4.0.15 - resolution: "@csstools/postcss-gradients-interpolation-method@npm:4.0.15" +"@csstools/postcss-gradients-interpolation-method@npm:^4.0.17": + version: 4.0.17 + resolution: "@csstools/postcss-gradients-interpolation-method@npm:4.0.17" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/dc0bbf6a4787d5ad3f9fe268dfa9776ecdc25b6cc0a49486bf53238341a339647f1e475240ead3cec1f4af9a237f6518ace015103e90ce8afe4d44539a566e04 + checksum: 10c0/465ac42856ca1a57aa2b9ea41ede31d9e2bcf2fe84345dbc182ae41f463069a0cfd41041b834b5133108c702cd85ecb8636b51b0b88fff8a221628639b59f386 languageName: node linkType: hard -"@csstools/postcss-hwb-function@npm:^3.0.13": - version: 3.0.13 - resolution: "@csstools/postcss-hwb-function@npm:3.0.13" +"@csstools/postcss-hwb-function@npm:^3.0.15": + version: 3.0.15 + resolution: "@csstools/postcss-hwb-function@npm:3.0.15" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/684c3d408ceb027e7276c4f25c9a17ef9bd52f0948268cf58b5184097e9b71f5364a41b42bab44691938c6fadffcba0c8e66f809a339a8b282f4a432d32d00ef + checksum: 10c0/fdfaeefbab1008ab1e4a98a2b45cc3db002b2724c404fa0600954b411a68b1fa4028286250bf9898eed10fa80c44e4d6b4e55f1aca073c3dfce8198a0aaedf3f languageName: node linkType: hard @@ -1761,17 +1761,17 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-light-dark-function@npm:^1.0.3": - version: 1.0.3 - resolution: "@csstools/postcss-light-dark-function@npm:1.0.3" +"@csstools/postcss-light-dark-function@npm:^1.0.5": + version: 1.0.5 + resolution: "@csstools/postcss-light-dark-function@npm:1.0.5" dependencies: - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/99a1b72aba08a6fa5c7271d42f4459d86f001fe83f533c0ed3d21556f53ee227f65f94cda1feee1aa910890fc42482f15a4dfb3edbc7afdad828ce8897d0c52b + checksum: 10c0/4fbeda98372d0da25d3ed87da09903c9a0a5d0b8c13cc9de82a98acce4a8f8367e5ba33bfc25c2534d10f2b1db9d5b4278df4ebab755e27ef2b03a95e0ebe264 languageName: node linkType: hard @@ -1813,42 +1813,42 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-logical-viewport-units@npm:^2.0.7": - version: 2.0.7 - resolution: "@csstools/postcss-logical-viewport-units@npm:2.0.7" +"@csstools/postcss-logical-viewport-units@npm:^2.0.9": + version: 2.0.9 + resolution: "@csstools/postcss-logical-viewport-units@npm:2.0.9" dependencies: - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/9493f5395ccfe88d0d0740e54f77f0c844afc79b164068fdd907aed75004b4252ba9423dea22194ad98114dd1a2e77c14e307604305d926425251d4ab3013949 + checksum: 10c0/25b01e36b08c571806d09046be63582dbebf97a4612df59be405fa8a92e6eebcd4e768ad7fbe53b0b8739d6ab04d56957964fb04d6a3ea129fc5f72e6d0adf95 languageName: node linkType: hard -"@csstools/postcss-media-minmax@npm:^1.1.4": - version: 1.1.4 - resolution: "@csstools/postcss-media-minmax@npm:1.1.4" +"@csstools/postcss-media-minmax@npm:^1.1.6": + version: 1.1.6 + resolution: "@csstools/postcss-media-minmax@npm:1.1.6" dependencies: - "@csstools/css-calc": "npm:^1.2.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" - "@csstools/media-query-list-parser": "npm:^2.1.9" + "@csstools/css-calc": "npm:^1.2.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" + "@csstools/media-query-list-parser": "npm:^2.1.11" peerDependencies: postcss: ^8.4 - checksum: 10c0/620bb85065195c72cf9c0abe9af822f9feeaf919b53bfd47ec09f75b644cb544bd967b09278c48f829348808b34c552718c1aa3eb5342e2dec983e22eb63b0a0 + checksum: 10c0/2cbfb3728a232c655d82f63d5ac7da36876d14e5fee5d62a0738efed40c58f20ef11f600395ade24d5063d750e8e093251dd93cc361f782b5a6c0e0f80288f51 languageName: node linkType: hard -"@csstools/postcss-media-queries-aspect-ratio-number-values@npm:^2.0.7": - version: 2.0.7 - resolution: "@csstools/postcss-media-queries-aspect-ratio-number-values@npm:2.0.7" +"@csstools/postcss-media-queries-aspect-ratio-number-values@npm:^2.0.9": + version: 2.0.9 + resolution: "@csstools/postcss-media-queries-aspect-ratio-number-values@npm:2.0.9" dependencies: - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" - "@csstools/media-query-list-parser": "npm:^2.1.9" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" + "@csstools/media-query-list-parser": "npm:^2.1.11" peerDependencies: postcss: ^8.4 - checksum: 10c0/d5d52a744f9a9466d86a506aab430811778dfa681d3f52f5486ee9b686390919eaae9ad356b84bc782d263227f35913ef68d9a6c3eefcfc38d8ffaccc9b94de0 + checksum: 10c0/d431d2900a7177c938d9dc2d5bdf3c1930758adc214cc72f94b34e6bbd02fd917c200dc81482db515519c97d4f1e766ba3200f3ec9b55081887f2f8111f68e20 languageName: node linkType: hard @@ -1875,18 +1875,18 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-oklab-function@npm:^3.0.14": - version: 3.0.14 - resolution: "@csstools/postcss-oklab-function@npm:3.0.14" +"@csstools/postcss-oklab-function@npm:^3.0.16": + version: 3.0.16 + resolution: "@csstools/postcss-oklab-function@npm:3.0.16" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/dfe0b12c2256dded995c64825fac9507be9c747d776cfa09eeefff6dee0efa5eed6a92a1ecba39069a751a7fc3cefa8891c34209a7a3c7ea33d356c95d01a02d + checksum: 10c0/9c67ee5f51116df16ab6baffa1b3c6c7aa93d53b836f421125ae8824075bd3cfaa1a93594466de0ac935c89c4fc8171e80974e1a15bafa23ea864e4cf1f1c1f2 languageName: node linkType: hard @@ -1901,18 +1901,18 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-relative-color-syntax@npm:^2.0.14": - version: 2.0.14 - resolution: "@csstools/postcss-relative-color-syntax@npm:2.0.14" +"@csstools/postcss-relative-color-syntax@npm:^2.0.16": + version: 2.0.16 + resolution: "@csstools/postcss-relative-color-syntax@npm:2.0.16" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/64cd5f8054e4403f4e25ed11a5b9d157098af639dbc30ac25b94660b3af489c0bacc49fc439cba1ccceefa4caa5831a913e3d1d889a9796cc6fbf3902c7c31c1 + checksum: 10c0/cdc965706212dcbc03394f55c79a0ad043d1e0174059c4d0d90e4267fe8e6fd9eef7cfed4f5bbc1f8e89c225c1c042ae792e115bba198eb2daae763d65f44679 languageName: node linkType: hard @@ -1927,16 +1927,16 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-stepped-value-functions@npm:^3.0.6": - version: 3.0.6 - resolution: "@csstools/postcss-stepped-value-functions@npm:3.0.6" +"@csstools/postcss-stepped-value-functions@npm:^3.0.8": + version: 3.0.8 + resolution: "@csstools/postcss-stepped-value-functions@npm:3.0.8" dependencies: - "@csstools/css-calc": "npm:^1.2.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-calc": "npm:^1.2.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" peerDependencies: postcss: ^8.4 - checksum: 10c0/a198aedc4fffe88909c92bfaa36031e6803e739a2578ba4a81c01b9f1525e6a6876d6ffacbbe21701298598dcade8b2ac8423d8ab0fc5d9f4ba86ed60f53cbca + checksum: 10c0/2be66aa769808245137be8ff14308aa17c3a0d75433f6fd6789114966a78c365dbf173d087e7ff5bc80118c75be2ff740baab83ed39fc0671980f6217779956b languageName: node linkType: hard @@ -1952,16 +1952,16 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-trigonometric-functions@npm:^3.0.6": - version: 3.0.6 - resolution: "@csstools/postcss-trigonometric-functions@npm:3.0.6" +"@csstools/postcss-trigonometric-functions@npm:^3.0.8": + version: 3.0.8 + resolution: "@csstools/postcss-trigonometric-functions@npm:3.0.8" dependencies: - "@csstools/css-calc": "npm:^1.2.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-calc": "npm:^1.2.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" peerDependencies: postcss: ^8.4 - checksum: 10c0/4b484af853d9eb59a4a4b1c063fcf48e2658bb2d6930dfab1d79e676986534687e6440b8cdcd2731ddcb7726537f4ed484208a2b80ef2c9359053762ba35e5e7 + checksum: 10c0/aeed8d1026f4a5cb7afafbadd739af84291d5bfcbcdef2f79b77174f003d0cd0c7f9deb3fe0b9377efab37ce9bb17a2499efd4af8211f5ff9eb01b878b0b62b3 languageName: node linkType: hard @@ -13147,18 +13147,18 @@ __metadata: languageName: node linkType: hard -"postcss-color-functional-notation@npm:^6.0.9": - version: 6.0.9 - resolution: "postcss-color-functional-notation@npm:6.0.9" +"postcss-color-functional-notation@npm:^6.0.11": + version: 6.0.11 + resolution: "postcss-color-functional-notation@npm:6.0.11" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/120f7bc23bf46dd1c008b3aa806fb02dd988ae180f9c0c10dca9f5ea3473bf20d7743aafae1441df5b4a3945a63ebb0dae1d4d55f7c8bcd34540529b627c4e3e + checksum: 10c0/7fd75e6881cf62f536f79dfc0ae1b709ea0b8b84833cce1671372711f6019ab4360c6a17089b654b2d376b87e7f9455b94f0d13b45ab0ab767e547b604709b3d languageName: node linkType: hard @@ -13212,46 +13212,46 @@ __metadata: languageName: node linkType: hard -"postcss-custom-media@npm:^10.0.4": - version: 10.0.4 - resolution: "postcss-custom-media@npm:10.0.4" +"postcss-custom-media@npm:^10.0.6": + version: 10.0.6 + resolution: "postcss-custom-media@npm:10.0.6" dependencies: - "@csstools/cascade-layer-name-parser": "npm:^1.0.9" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" - "@csstools/media-query-list-parser": "npm:^2.1.9" + "@csstools/cascade-layer-name-parser": "npm:^1.0.11" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" + "@csstools/media-query-list-parser": "npm:^2.1.11" peerDependencies: postcss: ^8.4 - checksum: 10c0/2384a40f0e38abe92fbfc707000b264e4bdfe65bd0086ab18c6aab71049198f9dd1431bc4f9bbf68f7cca86b4ff0da352bac4a6ecd04e3671b7ddf6ed6ec3d04 + checksum: 10c0/98a524bc46b780a86094bbe8007f1e577137da5490823631a683d4b3df4a13e40c5e1ab52380275a54f7011abfd98bb597c6293d964c14f9f22ec6cf9d75c550 languageName: node linkType: hard -"postcss-custom-properties@npm:^13.3.8": - version: 13.3.8 - resolution: "postcss-custom-properties@npm:13.3.8" +"postcss-custom-properties@npm:^13.3.10": + version: 13.3.10 + resolution: "postcss-custom-properties@npm:13.3.10" dependencies: - "@csstools/cascade-layer-name-parser": "npm:^1.0.9" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/cascade-layer-name-parser": "npm:^1.0.11" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/utilities": "npm:^1.0.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/03dd1918f897005b23d09615ebb2c3faf4a01cac67462069c9cfa87c024b2a878f64948b0cf668971bc0ca00cfc349080879b3864deb3808a32d52ff2b473319 + checksum: 10c0/52688fd0aaadccfdf4a3d86d3a2ab988163e8108088c5e33fc9145d261f75b92b8321c044a8161345abda10df5715d674330309dcc0c17f2980db5515f6a76d6 languageName: node linkType: hard -"postcss-custom-selectors@npm:^7.1.8": - version: 7.1.8 - resolution: "postcss-custom-selectors@npm:7.1.8" +"postcss-custom-selectors@npm:^7.1.10": + version: 7.1.10 + resolution: "postcss-custom-selectors@npm:7.1.10" dependencies: - "@csstools/cascade-layer-name-parser": "npm:^1.0.9" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/cascade-layer-name-parser": "npm:^1.0.11" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" postcss-selector-parser: "npm:^6.0.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/6a7d8248342177a222821531ea3b4008764362e4f7e8f7f2d5767e5880c37ffa39ac5adced2c686baeb9c1f4ed4c283fcc8a8d30ef3b4fc5f63d4ef9a691285e + checksum: 10c0/11311ae6f306420223c6bf926fb1798738f3aa525a267de204de8e8ee9de467bf63b580d9ad5dbb0fff4bd9266770a3fa7e27a24af08a2e0a4115d0727d1d043 languageName: node linkType: hard @@ -13367,18 +13367,18 @@ __metadata: languageName: node linkType: hard -"postcss-lab-function@npm:^6.0.14": - version: 6.0.14 - resolution: "postcss-lab-function@npm:6.0.14" +"postcss-lab-function@npm:^6.0.16": + version: 6.0.16 + resolution: "postcss-lab-function@npm:6.0.16" dependencies: - "@csstools/css-color-parser": "npm:^2.0.0" - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" + "@csstools/css-color-parser": "npm:^2.0.2" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/0b5d998ddb98ec6243448f1eca216f6e23872431885b152843feef1e844fc5b6b3ebe16ea8940f3d6abea732aa0c51b2ec0e57437e4326e5b2cb2bcb949e6d9f + checksum: 10c0/ba8717cd8a197ec17acaac1b61631cd4403f07bd406b0c92f2e430a55e3f786cd6c338b626c3326e9178a0f3e58ff838ebaded19f480f39197a9cb17349ecdcd languageName: node linkType: hard @@ -13698,37 +13698,37 @@ __metadata: linkType: hard "postcss-preset-env@npm:^9.5.2": - version: 9.5.9 - resolution: "postcss-preset-env@npm:9.5.9" + version: 9.5.11 + resolution: "postcss-preset-env@npm:9.5.11" dependencies: "@csstools/postcss-cascade-layers": "npm:^4.0.4" - "@csstools/postcss-color-function": "npm:^3.0.14" - "@csstools/postcss-color-mix-function": "npm:^2.0.14" - "@csstools/postcss-exponential-functions": "npm:^1.0.5" + "@csstools/postcss-color-function": "npm:^3.0.16" + "@csstools/postcss-color-mix-function": "npm:^2.0.16" + "@csstools/postcss-exponential-functions": "npm:^1.0.7" "@csstools/postcss-font-format-keywords": "npm:^3.0.2" - "@csstools/postcss-gamut-mapping": "npm:^1.0.7" - "@csstools/postcss-gradients-interpolation-method": "npm:^4.0.15" - "@csstools/postcss-hwb-function": "npm:^3.0.13" + "@csstools/postcss-gamut-mapping": "npm:^1.0.9" + "@csstools/postcss-gradients-interpolation-method": "npm:^4.0.17" + "@csstools/postcss-hwb-function": "npm:^3.0.15" "@csstools/postcss-ic-unit": "npm:^3.0.6" "@csstools/postcss-initial": "npm:^1.0.1" "@csstools/postcss-is-pseudo-class": "npm:^4.0.6" - "@csstools/postcss-light-dark-function": "npm:^1.0.3" + "@csstools/postcss-light-dark-function": "npm:^1.0.5" "@csstools/postcss-logical-float-and-clear": "npm:^2.0.1" "@csstools/postcss-logical-overflow": "npm:^1.0.1" "@csstools/postcss-logical-overscroll-behavior": "npm:^1.0.1" "@csstools/postcss-logical-resize": "npm:^2.0.1" - "@csstools/postcss-logical-viewport-units": "npm:^2.0.7" - "@csstools/postcss-media-minmax": "npm:^1.1.4" - "@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^2.0.7" + "@csstools/postcss-logical-viewport-units": "npm:^2.0.9" + "@csstools/postcss-media-minmax": "npm:^1.1.6" + "@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^2.0.9" "@csstools/postcss-nested-calc": "npm:^3.0.2" "@csstools/postcss-normalize-display-values": "npm:^3.0.2" - "@csstools/postcss-oklab-function": "npm:^3.0.14" + "@csstools/postcss-oklab-function": "npm:^3.0.16" "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" - "@csstools/postcss-relative-color-syntax": "npm:^2.0.14" + "@csstools/postcss-relative-color-syntax": "npm:^2.0.16" "@csstools/postcss-scope-pseudo-class": "npm:^3.0.1" - "@csstools/postcss-stepped-value-functions": "npm:^3.0.6" + "@csstools/postcss-stepped-value-functions": "npm:^3.0.8" "@csstools/postcss-text-decoration-shorthand": "npm:^3.0.6" - "@csstools/postcss-trigonometric-functions": "npm:^3.0.6" + "@csstools/postcss-trigonometric-functions": "npm:^3.0.8" "@csstools/postcss-unset-value": "npm:^3.0.1" autoprefixer: "npm:^10.4.19" browserslist: "npm:^4.22.3" @@ -13738,12 +13738,12 @@ __metadata: cssdb: "npm:^8.0.0" postcss-attribute-case-insensitive: "npm:^6.0.3" postcss-clamp: "npm:^4.1.0" - postcss-color-functional-notation: "npm:^6.0.9" + postcss-color-functional-notation: "npm:^6.0.11" postcss-color-hex-alpha: "npm:^9.0.4" postcss-color-rebeccapurple: "npm:^9.0.3" - postcss-custom-media: "npm:^10.0.4" - postcss-custom-properties: "npm:^13.3.8" - postcss-custom-selectors: "npm:^7.1.8" + postcss-custom-media: "npm:^10.0.6" + postcss-custom-properties: "npm:^13.3.10" + postcss-custom-selectors: "npm:^7.1.10" postcss-dir-pseudo-class: "npm:^8.0.1" postcss-double-position-gradients: "npm:^5.0.6" postcss-focus-visible: "npm:^9.0.1" @@ -13751,7 +13751,7 @@ __metadata: postcss-font-variant: "npm:^5.0.0" postcss-gap-properties: "npm:^5.0.1" postcss-image-set-function: "npm:^6.0.3" - postcss-lab-function: "npm:^6.0.14" + postcss-lab-function: "npm:^6.0.16" postcss-logical: "npm:^7.0.1" postcss-nesting: "npm:^12.1.2" postcss-opacity-percentage: "npm:^2.0.0" @@ -13763,7 +13763,7 @@ __metadata: postcss-selector-not: "npm:^7.0.2" peerDependencies: postcss: ^8.4 - checksum: 10c0/dbe020e3fc08f0b71a3ee9d3c8a66a93bb6ba62281ac89fa59c82b8632ca58d6a911ddd9c65f15355c36aad63477633fc101cc0f3ce494dbc757193ba42eb61c + checksum: 10c0/9460f4ce18cf1af7582d0a1f366151f59b6e9b0c7cbb62e59081dc91da14760a749f59fa52bc190e5e2c8fd531952c647719d19c4740aa1a0ebcb93f075ad931 languageName: node linkType: hard From 9be2c02e52b9c3534fa1bd16ade00a135034d2cb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 10:36:29 +0200 Subject: [PATCH 091/658] New Crowdin Translations (automated) (#30169) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ar.json | 39 +- app/javascript/mastodon/locales/de.json | 4 +- app/javascript/mastodon/locales/ja.json | 9 + app/javascript/mastodon/locales/sl.json | 13 + app/javascript/mastodon/locales/sq.json | 14 + config/locales/ar.yml | 1 + config/locales/devise.ia.yml | 3 + config/locales/doorkeeper.ia.yml | 1 + config/locales/doorkeeper.sq.yml | 1 + config/locales/ia.yml | 584 +++++++++++++++++++++++- config/locales/ja.yml | 1 + config/locales/lt.yml | 20 +- config/locales/pt-PT.yml | 1 + config/locales/simple_form.ar.yml | 1 + config/locales/simple_form.he.yml | 3 + config/locales/simple_form.ia.yml | 113 +++++ config/locales/simple_form.ja.yml | 4 + config/locales/simple_form.pt-PT.yml | 4 + config/locales/simple_form.sq.yml | 4 + config/locales/simple_form.th.yml | 2 + config/locales/sk.yml | 1 + config/locales/sl.yml | 1 + config/locales/sq.yml | 1 + config/locales/th.yml | 1 + 24 files changed, 807 insertions(+), 19 deletions(-) diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index dd13f10aa3..68e32dd2aa 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -5,7 +5,7 @@ "about.domain_blocks.no_reason_available": "السبب غير متوفر", "about.domain_blocks.preamble": "يسمح لك ماستدون عموماً بعرض المحتوى من المستخدمين من أي خادم آخر في الفدرالية والتفاعل معهم. وهذه هي الاستثناءات التي وضعت على هذا الخادم بالذات.", "about.domain_blocks.silenced.explanation": "عموماً، لن ترى ملفات التعريف والمحتوى من هذا الخادم، إلا إذا كنت تبحث عنه بشكل صريح أو تختار أن تتابعه.", - "about.domain_blocks.silenced.title": "تم كتمه", + "about.domain_blocks.silenced.title": "محدود", "about.domain_blocks.suspended.explanation": "لن يتم معالجة أي بيانات من هذا الخادم أو تخزينها أو تبادلها، مما يجعل أي تفاعل أو اتصال مع المستخدمين من هذا الخادم مستحيلا.", "about.domain_blocks.suspended.title": "مُعلّق", "about.not_available": "لم يتم توفير هذه المعلومات على هذا الخادم.", @@ -21,7 +21,7 @@ "account.blocked": "محظور", "account.browse_more_on_origin_server": "تصفح المزيد في الملف الشخصي الأصلي", "account.cancel_follow_request": "إلغاء طلب المتابعة", - "account.copy": "نسخ الرابط إلى الملف الشخصي", + "account.copy": "نسخ الرابط إلى الحساب", "account.direct": "إشارة خاصة لـ @{name}", "account.disable_notifications": "توقف عن إشعاري عندما ينشر @{name}", "account.domain_blocked": "اسم النِّطاق محظور", @@ -32,7 +32,7 @@ "account.featured_tags.last_status_never": "لا توجد رسائل", "account.featured_tags.title": "وسوم {name} المميَّزة", "account.follow": "متابعة", - "account.follow_back": "تابعه بدورك", + "account.follow_back": "رد المتابعة", "account.followers": "مُتابِعون", "account.followers.empty": "لا أحدَ يُتابع هذا المُستخدم إلى حد الآن.", "account.followers_counter": "{count, plural, zero{لا مُتابع} one {مُتابعٌ واحِد} two {مُتابعانِ اِثنان} few {{counter} مُتابِعين} many {{counter} مُتابِعًا} other {{counter} مُتابع}}", @@ -89,12 +89,12 @@ "announcement.announcement": "إعلان", "attachments_list.unprocessed": "(غير معالَج)", "audio.hide": "إخفاء المقطع الصوتي", - "block_modal.remote_users_caveat": "Do t’i kërkojmë shërbyesit {domain} të respektojë vendimin tuaj. Por, pajtimi s’është i garantuar, ngaqë disa shërbyes mund t’i trajtojnë ndryshe bllokimet. Psotimet publike mundet të jenë ende të dukshme për përdorues pa bërë hyrje në llogari.", - "block_modal.show_less": "اعرض أقلّ", + "block_modal.remote_users_caveat": "سوف نطلب من الخادم {domain} أن يحترم قرارك، لكن الالتزام غير مضمون لأن بعض الخواديم قد تتعامل مع نصوص الكتل بشكل مختلف. قد تظل المنشورات العامة مرئية للمستخدمين غير المسجلين الدخول.", + "block_modal.show_less": "أظهر الأقل", "block_modal.show_more": "أظهر المزيد", "block_modal.they_cant_mention": "لن يستطيع ذِكرك أو متابعتك.", "block_modal.they_cant_see_posts": "لن يستطيع رؤية منشوراتك ولن ترى منشوراته.", - "block_modal.they_will_know": "يمكنه أن يرى أنه قد تم حجبه.", + "block_modal.they_will_know": "يمكنه أن يرى أنه قد تم حظره.", "block_modal.title": "أتريد حظر المستخدم؟", "block_modal.you_wont_see_mentions": "لن تر المنشورات التي يُشار فيهم إليه.", "boost_modal.combo": "يُمكنك الضّغط على {combo} لتخطي هذا في المرة المُقبلة", @@ -220,7 +220,7 @@ "domain_pill.activitypub_lets_connect": "يتيح لك التواصل والتفاعل مع الناس ليس فقط على ماستدون، ولكن عبر تطبيقات اجتماعية مختلفة أيضا.", "domain_pill.activitypub_like_language": "إنّ ActivityPub مثل لغة ماستدون التي يتحدث بها مع شبكات اجتماعية أخرى.", "domain_pill.server": "الخادِم", - "domain_pill.their_handle": "مُعرِّفُه:", + "domain_pill.their_handle": "مُعرفه:", "domain_pill.their_server": "بيتهم الرقمي، حيث تُستضاف كافة منشوراتهم.", "domain_pill.their_username": "مُعرّفُهم الفريد على الخادم. من الممكن العثور على مستخدمين بنفس اسم المستخدم على خوادم مختلفة.", "domain_pill.username": "اسم المستخدم", @@ -308,6 +308,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "هذا الملف الشخصي مشابه للملفات الشخصية التي تابعتها مؤخرا.", "follow_suggestions.personalized_suggestion": "توصية مخصصة", "follow_suggestions.popular_suggestion": "توصية رائجة", + "follow_suggestions.popular_suggestion_longer": "رائج على {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "مشابهة لمواصفات الملفات الشخصية التي تابعتَها حديثًا", "follow_suggestions.view_all": "عرض الكل", "follow_suggestions.who_to_follow": "حسابات للمُتابَعة", "followed_tags": "الوسوم المتابَعة", @@ -360,8 +362,8 @@ "interaction_modal.title.reply": "الرد على منشور {name}", "intervals.full.days": "{number, plural, one {# يوم} other {# أيام}}", "intervals.full.hours": "{number, plural, one {# ساعة} other {# ساعات}}", - "intervals.full.minutes": "{number, plural, one {# دقيقة} other {# دقائق}}", - "keyboard_shortcuts.back": "للعودة", + "intervals.full.minutes": "{number, plural, one {دقيقة واحدة}two {دقيقتان} other {# دقائق}}", + "keyboard_shortcuts.back": "للرجوع", "keyboard_shortcuts.blocked": "لفتح قائمة المستخدمين المحظورين", "keyboard_shortcuts.boost": "لإعادة النشر", "keyboard_shortcuts.column": "للتركيز على منشور على أحد الأعمدة", @@ -421,7 +423,9 @@ "loading_indicator.label": "جاري التحميل…", "media_gallery.toggle_visible": "{number, plural, zero {} one {اخف الصورة} two {اخف الصورتين} few {اخف الصور} many {اخف الصور} other {اخف الصور}}", "moved_to_account_banner.text": "حسابك {disabledAccount} معطل حاليًا لأنك انتقلت إلى {movedToAccount}.", + "mute_modal.hide_from_notifications": "إخفاء من قائمة الإشعارات", "mute_modal.hide_options": "إخفاء الخيارات", + "mute_modal.indefinite": "إلى أن أفسخ كتمها", "mute_modal.show_options": "إظهار الخيارات", "mute_modal.they_can_mention_and_follow": "سيكون بإمكانه الإشارة إليك ومتابعتك، لكنك لن تره.", "mute_modal.they_wont_know": "لن يَعرف أنه قد تم كتمه.", @@ -460,10 +464,20 @@ "notification.follow": "يتابعك {name}", "notification.follow_request": "لقد طلب {name} متابعتك", "notification.mention": "{name} ذكرك", + "notification.moderation-warning.learn_more": "اعرف المزيد", + "notification.moderation_warning.action_disable": "تم تعطيل حسابك.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "بعض من منشوراتك تم تصنيفها على أنها حساسة.", + "notification.moderation_warning.action_none": "لقد تلقى حسابك تحذيرا بالإشراف.", + "notification.moderation_warning.action_sensitive": "سيتم وضع علامة على منشوراتك على أنها حساسة من الآن فصاعدا.", + "notification.moderation_warning.action_suspend": "لقد تم تعليق حسابك.", "notification.own_poll": "انتهى استطلاعك للرأي", "notification.poll": "لقد انتهى استطلاع رأي شاركتَ فيه", "notification.reblog": "قام {name} بمشاركة منشورك", + "notification.relationships_severance_event": "فقدت الاتصالات مع {name}", + "notification.relationships_severance_event.account_suspension": "قام مشرف من {from} بتعليق {target}، مما يعني أنك لم يعد بإمكانك تلقي التحديثات منهم أو التفاعل معهم.", + "notification.relationships_severance_event.domain_block": "قام مشرف من {from} بحظر {target}، بما في ذلك {followersCount} من متابعينك و {followingCount, plural, one {# حساب} other {# حسابات}} تتابعها.", "notification.relationships_severance_event.learn_more": "اعرف المزيد", + "notification.relationships_severance_event.user_domain_block": "لقد قمت بحظر {target}، مما أدى إلى إزالة {followersCount} من متابعينك و {followingCount, plural, one {# حساب} other {# حسابات}} تتابعها.", "notification.status": "{name} نشر للتو", "notification.update": "عدّلَ {name} منشورًا", "notification_requests.accept": "موافقة", @@ -503,10 +517,15 @@ "notifications.permission_denied": "تنبيهات سطح المكتب غير متوفرة بسبب رفض أذونات المتصفح مسبقاً", "notifications.permission_denied_alert": "لا يمكن تفعيل إشعارات سطح المكتب، لأن إذن المتصفح قد تم رفضه سابقاً", "notifications.permission_required": "إشعارات سطح المكتب غير متوفرة لأنه لم يتم منح الإذن المطلوب.", + "notifications.policy.filter_new_accounts.hint": "تم إنشاؤها منذ {days, plural, zero {}one {يوم واحد} two {يومان} few {# أيام} many {# أيام} other {# أيام}}", "notifications.policy.filter_new_accounts_title": "حسابات جديدة", + "notifications.policy.filter_not_followers_hint": "بما في ذلك الأشخاص الذين يتابعونك أقل من {days, plural, zero {}one {يوم واحد} two {يومان} few {# أيام} many {# أيام} other {# أيام}}", "notifications.policy.filter_not_followers_title": "أشخاص لا يتابعونك", "notifications.policy.filter_not_following_hint": "حتى توافق عليهم يدويا", "notifications.policy.filter_not_following_title": "أشخاص لا تتابعهم", + "notifications.policy.filter_private_mentions_hint": "تمت تصفيته إلا إذا أن يكون ردًا على ذكرك أو إذا كنت تتابع الحساب", + "notifications.policy.filter_private_mentions_title": "إشارات خاصة غير مرغوب فيها", + "notifications.policy.title": "تصفية الإشعارات من…", "notifications_permission_banner.enable": "تفعيل إشعارات سطح المكتب", "notifications_permission_banner.how_to_control": "لتلقي الإشعارات عندما لا يكون ماستدون مفتوح، قم بتفعيل إشعارات سطح المكتب، يمكنك التحكم بدقة في أنواع التفاعلات التي تولد إشعارات سطح المكتب من خلال زر الـ{icon} أعلاه بمجرد تفعيلها.", "notifications_permission_banner.title": "لا تفوت شيئاً أبداً", @@ -687,6 +706,7 @@ "status.edited_x_times": "عُدّل {count, plural, zero {} one {مرةً واحدة} two {مرّتان} few {{count} مرات} many {{count} مرة} other {{count} مرة}}", "status.embed": "إدماج", "status.favourite": "فضّل", + "status.favourites": "{count, plural, zero {}one {مفضلة واحدة} two {مفضلتان} few {# مفضلات} many {# مفضلات} other {# مفضلات}}", "status.filter": "تصفية هذه الرسالة", "status.filtered": "مُصفّى", "status.hide": "إخفاء المنشور", @@ -707,6 +727,7 @@ "status.reblog": "إعادة النشر", "status.reblog_private": "إعادة النشر إلى الجمهور الأصلي", "status.reblogged_by": "شارَكَه {name}", + "status.reblogs": "{count, plural, one {تعزيز واحد} two {تعزيزتان} few {# تعزيزات} many {# تعزيزات} other {# تعزيزات}}", "status.reblogs.empty": "لم يقم أي أحد بمشاركة هذا المنشور بعد. عندما يقوم أحدهم بذلك سوف يظهر هنا.", "status.redraft": "إزالة وإعادة الصياغة", "status.remove_bookmark": "احذفه مِن الفواصل المرجعية", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 59d3d0965a..5776641079 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -331,7 +331,7 @@ "footer.source_code": "Quellcode anzeigen", "footer.status": "Status", "generic.saved": "Gespeichert", - "getting_started.heading": "Auf geht’s!", + "getting_started.heading": "Auf gehts!", "hashtag.column_header.tag_mode.all": "und {additional}", "hashtag.column_header.tag_mode.any": "oder {additional}", "hashtag.column_header.tag_mode.none": "ohne {additional}", @@ -400,7 +400,7 @@ "keyboard_shortcuts.requests": "Liste der Follower-Anfragen aufrufen", "keyboard_shortcuts.search": "Suchleiste fokussieren", "keyboard_shortcuts.spoilers": "Feld für Inhaltswarnung anzeigen/ausblenden", - "keyboard_shortcuts.start": "„Auf geht’s!“ öffnen", + "keyboard_shortcuts.start": "„Auf gehts!“ öffnen", "keyboard_shortcuts.toggle_hidden": "Beitragstext hinter der Inhaltswarnung anzeigen/ausblenden", "keyboard_shortcuts.toggle_sensitivity": "Medien anzeigen/ausblenden", "keyboard_shortcuts.toot": "Neuen Beitrag erstellen", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index c11e4a2afd..6e590678fb 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -473,6 +473,15 @@ "notification.follow": "{name}さんにフォローされました", "notification.follow_request": "{name}さんがあなたにフォローリクエストしました", "notification.mention": "{name}さんがあなたに返信しました", + "notification.moderation-warning.learn_more": "さらに詳しく", + "notification.moderation_warning": "あなたは管理者からの警告を受けています。", + "notification.moderation_warning.action_delete_statuses": "あなたによるいくつかの投稿が削除されました。", + "notification.moderation_warning.action_disable": "あなたのアカウントは無効になりました。", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "あなたの投稿のいくつかは閲覧注意として判定されています。", + "notification.moderation_warning.action_none": "あなたのアカウントは管理者からの警告を受けています。", + "notification.moderation_warning.action_sensitive": "あなたの投稿はこれから閲覧注意としてマークされます。", + "notification.moderation_warning.action_silence": "あなたのアカウントは制限されています。", + "notification.moderation_warning.action_suspend": "あなたのアカウントは停止されました。", "notification.own_poll": "アンケートが終了しました", "notification.poll": "アンケートが終了しました", "notification.reblog": "{name}さんがあなたの投稿をブーストしました", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index ed4fa8dfaf..7806abc6b5 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Čeprav vaš račun ni zaklenjen, zaposleni pri {domain} menijo, da bi morda želeli pregledati zahteve za sledenje teh računov ročno.", "follow_suggestions.curated_suggestion": "Izbor osebja", "follow_suggestions.dismiss": "Ne pokaži več", + "follow_suggestions.featured_longer": "Osebno izbrala ekipa {domain}", + "follow_suggestions.friends_of_friends_longer": "Priljubljeno med osebami, ki jim sledite", "follow_suggestions.hints.featured": "Ta profil so izbrali skrbniki strežnika {domain}.", "follow_suggestions.hints.friends_of_friends": "Ta profil je priljubljen med osebami, ki jim sledite.", "follow_suggestions.hints.most_followed": "Ta profil na strežniku {domain} je en izmed najbolj sledenih.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Ta profil je podoben profilom, ki ste jim nedavno začeli slediti.", "follow_suggestions.personalized_suggestion": "Osebno prilagojen predlog", "follow_suggestions.popular_suggestion": "Priljubljen predlog", + "follow_suggestions.popular_suggestion_longer": "Priljubljeno na {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Podobno profilom, ki ste jim pred kratkim sledili", "follow_suggestions.view_all": "Pokaži vse", "follow_suggestions.who_to_follow": "Komu slediti", "followed_tags": "Sledeni ključniki", @@ -469,6 +473,15 @@ "notification.follow": "{name} vam sledi", "notification.follow_request": "{name} vam želi slediti", "notification.mention": "{name} vas je omenil/a", + "notification.moderation-warning.learn_more": "Več o tem", + "notification.moderation_warning": "Prejeli ste opozorilo moderatorjev", + "notification.moderation_warning.action_delete_statuses": "Nekatere vaše objave so odstranjene.", + "notification.moderation_warning.action_disable": "Vaš račun je bil onemogočen.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nekatere vaše objave so bile označene kot občutljive.", + "notification.moderation_warning.action_none": "Vaš račun je prejel opozorilo moderatorjev.", + "notification.moderation_warning.action_sensitive": "Vaše objave bodo odslej označene kot občutljive.", + "notification.moderation_warning.action_silence": "Vaš račun je bil omejen.", + "notification.moderation_warning.action_suspend": "Vaš račun je bil suspendiran.", "notification.own_poll": "Vaša anketa je zaključena", "notification.poll": "Anketa, v kateri ste sodelovali, je zaključena", "notification.reblog": "{name} je izpostavila/a vašo objavo", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index da35b3d43b..a25eab9cbf 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -297,6 +297,7 @@ "filter_modal.select_filter.subtitle": "Përdorni një kategori ekzistuese, ose krijoni një të re", "filter_modal.select_filter.title": "Filtroje këtë postim", "filter_modal.title.status": "Filtroni një postim", + "filtered_notifications_banner.mentions": "{count, plural, one {përmendje} other {përmendje}}", "filtered_notifications_banner.pending_requests": "Njoftime prej {count, plural, =0 {askujt} one {një personi} other {# vetësh}} që mund të njihni", "filtered_notifications_banner.title": "Njoftime të filtruar", "firehose.all": "Krejt", @@ -307,6 +308,8 @@ "follow_requests.unlocked_explanation": "Edhe pse llogaria juaj s’është e kyçur, ekipi i {domain} mendoi se mund të donit të shqyrtonit dorazi kërkesa ndjekjeje prej këtyre llogarive.", "follow_suggestions.curated_suggestion": "Zgjedhur nga ekipi", "follow_suggestions.dismiss": "Mos shfaq më", + "follow_suggestions.featured_longer": "Zgjedhur enkas nga ekipi {domain}", + "follow_suggestions.friends_of_friends_longer": "Popullore mes personash që ndiqni", "follow_suggestions.hints.featured": "Ky profil është zgjedhur nga ekipi {domain}.", "follow_suggestions.hints.friends_of_friends": "Ky profil është popullor mes personave që ndiqni.", "follow_suggestions.hints.most_followed": "Ky profil është një nga më të ndjekur në {domain}.", @@ -314,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Ky profil është i ngjashëm me profile që keni ndjekur tani afër.", "follow_suggestions.personalized_suggestion": "Sugjerim i personalizuar", "follow_suggestions.popular_suggestion": "Sugjerim popullor", + "follow_suggestions.popular_suggestion_longer": "Popullore në {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "I ngjashëm me profile që keni zënë të ndiqni së fundi", "follow_suggestions.view_all": "Shihni krejt", "follow_suggestions.who_to_follow": "Cilët të ndiqen", "followed_tags": "Hashtag-ë të ndjekur", @@ -468,6 +473,15 @@ "notification.follow": "{name} zuri t’ju ndjekë", "notification.follow_request": "{name} ka kërkuar t’ju ndjekë", "notification.mention": "{name} ju ka përmendur", + "notification.moderation-warning.learn_more": "Mësoni më tepër", + "notification.moderation_warning": "Keni marrë një sinjalizim moderimi", + "notification.moderation_warning.action_delete_statuses": "Disa nga postimet tuaja janë hequr.", + "notification.moderation_warning.action_disable": "Llogaria juaj është çaktivizuar.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Disa prej postimeve tuaja u është vënë shenjë si me spec.", + "notification.moderation_warning.action_none": "Llogaria juaj ka marrë një sinjalizim moderimi.", + "notification.moderation_warning.action_sensitive": "Postimeve tuaja do t’u vihet shenjë si me spec, nga tani e tutje.", + "notification.moderation_warning.action_silence": "Llogaria juaj është kufizuar.", + "notification.moderation_warning.action_suspend": "Llogaria juaj është pezulluar.", "notification.own_poll": "Pyetësori juaj ka përfunduar", "notification.poll": "Ka përfunduar një pyetësor ku keni votuar", "notification.reblog": "{name} përforcoi mesazhin tuaj", diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 93a0720b8a..02ba56d0b2 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -804,6 +804,7 @@ ar: desc_html: ويعتمد هذا على نصوص برمجية خارجية من hCaptcha، والتي قد تكون مصدر قلق يتعلق بالأمان والخصوصية. بالإضافة إلى ذلك، قد يؤدي ذلك إلى جعل عملية التسجيل أقل سهولة بالنسبة لبعض الأشخاص (وخاصة المعاقين). لهذه الأسباب، يرجى النظر في تدابير بديلة مثل التسجيل على أساس الموافقة أو على أساس الدعوة. title: مطالبة المستخدمين الجدد بحل اختبار CAPTCHA لتأكيد حساباتهم content_retention: + danger_zone: منطقة خطرة preamble: التحكم في كيفية تخزين المحتوى الذي ينشئه المستخدم في ماستدون. title: الاحتفاظ بالمحتوى default_noindex: diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index 6c89f4c6d4..5687507818 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -23,8 +23,11 @@ ia: action_with_app: Confirmar e retornar a %{app} title: Verificar adresse de e-mail email_changed: + explanation: 'Le adresse de e-mail pro tu conto essera cambiate a:' + subject: 'Mastodon: E-mail cambiate' title: Nove adresse de e-mail password_change: + explanation: Le contrasigno de tu conto ha essite cambiate. subject: 'Mastodon: Contrasigno cambiate' title: Contrasigno cambiate reconfirmation_instructions: diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index fd7d7a0836..86bd1ad985 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -17,6 +17,7 @@ ia: authorize: Autorisar cancel: Cancellar edit: Modificar + submit: Submitter confirmations: destroy: Es tu secur? edit: diff --git a/config/locales/doorkeeper.sq.yml b/config/locales/doorkeeper.sq.yml index 308a5429a6..793819c597 100644 --- a/config/locales/doorkeeper.sq.yml +++ b/config/locales/doorkeeper.sq.yml @@ -174,6 +174,7 @@ sq: read:filters: të shohë filtrat tuaj read:follows: të shohë ndjekësit tuaj read:lists: të shohë listat tuaja + read:me: të shohë vetëm hollësi elementare të llogarisë tuaj read:mutes: të shohë ç’keni heshtuar read:notifications: të shohë njoftimet tuaja read:reports: të shohë raportimet tuaja diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 59dd2dbc0f..85d7c0ed85 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -106,6 +106,9 @@ ia: pending: Attende revision perform_full_suspension: Suspender previous_strikes: Previe admonitiones + previous_strikes_description_html: + one: Iste conto ha un admonition. + other: Iste conto ha %{count} admonitiones. promote: Promover protocol: Protocollo public: Public @@ -159,10 +162,10 @@ ia: undo_suspension: Disfacer le suspension unsilenced_msg: Le limite del conto de %{username} ha essite cancellate unsubscribe: Desubscriber - unsuspended_msg: Annullate suspension del conto %{username} con successo + unsuspended_msg: Le suspension del conto %{username} ha essite annullate username: Nomine de usator view_domain: Vider summario de dominio - warn: Avisar + warn: Advertir web: Web whitelisted: Permittite pro federation action_logs: @@ -244,37 +247,102 @@ ia: create_user_role_html: "%{name} creava rolo de %{target}" demote_user_html: "%{name} degradava usator %{target}" destroy_announcement_html: "%{name} deleva annuncio %{target}" + destroy_canonical_email_block_html: "%{name} disblocava email con le hash %{target}" destroy_custom_emoji_html: "%{name} deleva emoji %{target}" + destroy_domain_allow_html: "%{name} impediva le federation con dominio %{target}" destroy_domain_block_html: "%{name} disblocava dominio %{target}" + destroy_email_domain_block_html: "%{name} disblocava le dominio email %{target}" + destroy_instance_html: "%{name} purgava le dominio %{target}" + destroy_ip_block_html: "%{name} deleva le regula pro IP %{target}" + destroy_status_html: "%{name} removeva le message de %{target}" + destroy_unavailable_domain_html: "%{name} resumeva le consignation al dominio %{target}" destroy_user_role_html: "%{name} deleva le rolo de %{target}" + disable_2fa_user_html: "%{name} disactivava le authentication a duo factores pro le usator %{target}" + disable_custom_emoji_html: "%{name} disactivava le emoticone %{target}" + disable_sign_in_token_auth_user_html: "%{name} disactivava authentication per testimonio via email pro %{target}" + disable_user_html: "%{name} disactivava le accesso pro le usator %{target}" + enable_custom_emoji_html: "%{name} activava le emoticone %{target}" + enable_sign_in_token_auth_user_html: "%{name} activava le authentication per testimonio via email pro %{target}" + enable_user_html: "%{name} activava le accesso pro le usator %{target}" + memorialize_account_html: "%{name} mutava le conto de %{target} in un pagina commemorative" + promote_user_html: "%{name} promoveva le usator %{target}" + reject_appeal_html: "%{name} refusava le appello del decision de moderation de %{target}" + reject_user_html: "%{name} refusava le inscription de %{target}" + remove_avatar_user_html: "%{name} removeva le avatar de %{target}" + reopen_report_html: "%{name} reaperiva le reporto %{target}" + resend_user_html: "%{name} reinviava le email de confirmation pro %{target}" + reset_password_user_html: "%{name} reinitialisava le contrasigno del usator %{target}" + resolve_report_html: "%{name} resolveva le reporto %{target}" + sensitive_account_html: "%{name} marcava como sensibile le medios de %{target}" + silence_account_html: "%{name} limitava le conto de %{target}" + suspend_account_html: "%{name} suspendeva le conto de %{target}" + unassigned_report_html: "%{name} de-assignava le reporto %{target}" + unblock_email_account_html: "%{name} disblocava le adresse email de %{target}" + unsensitive_account_html: "%{name} dismarcava como sensibile le medios de %{target}" + unsilence_account_html: "%{name} removeva le limite del conto de %{target}" + unsuspend_account_html: "%{name} removeva le suspension del conto de %{target}" + update_announcement_html: "%{name} actualisava le annuncio %{target}" + update_custom_emoji_html: "%{name} actualisava le emoticone %{target}" + update_domain_block_html: "%{name} actualisava le blocada de dominio pro %{target}" + update_ip_block_html: "%{name} cambiava le regula pro IP %{target}" + update_status_html: "%{name} actualisava le message per %{target}" + update_user_role_html: "%{name} cambiava le rolo de %{target}" deleted_account: conto delite + empty: Nulle registrationes trovate. + filter_by_action: Filtrar per action + filter_by_user: Filtrar per usator + title: Registro de inspection announcements: destroyed_msg: Annuncio delite con successo! edit: title: Modificar annuncio empty: Necun annuncios trovate. + live: Al vivo new: create: Crear annuncio title: Nove annuncio publish: Publicar published_msg: Annuncio publicate con successo! + scheduled_for: Programmate pro %{time} + scheduled_msg: Annuncio programmate pro le publication! title: Annuncios + unpublish: Depublicar + unpublished_msg: Le publication del annuncio ha essite disfacite! + updated_msg: Annuncio actualisate con successo! + critical_update_pending: Actualisation critic pendente custom_emojis: + assign_category: Assignar categoria by_domain: Dominio copied_msg: Copia local del emoji create con successo copy: Copiar + copy_failed_msg: Impossibile crear un copia local de ille emoticone create_new_category: Crear nove categoria created_msg: Emoji create con successo! delete: Deler + destroyed_msg: Emoticone destruite con successo destroyed! disable: Disactivar disabled: Disactivate disabled_msg: Emoji disactivate con successo + emoji: Emoticone enable: Activar enabled: Activate enabled_msg: Emoji activate con successo + image_hint: PNG o GIF usque %{size} + list: Listar + listed: Listate new: title: Adder nove emoji personalisate + no_emoji_selected: Nulle emoticones ha essite cambiate perque nulle ha essite seligite + not_permitted: Tu non es autorisate a exequer iste action + overwrite: Superscriber + shortcode: Via breve + shortcode_hint: Al minus 2 characteres, solo characteres alphanumeric e lineettas basse title: Emojis personalisate + uncategorized: Sin categoria + unlist: Non listar + unlisted: Non listate + update_failed_msg: Impossibile actualisar ille emoticone + updated_msg: Emoticone actualisate con successo! upload: Incargar dashboard: active_users: usatores active @@ -282,71 +350,180 @@ ia: media_storage: Immagazinage de medios new_users: nove usatores opened_reports: reportos aperte + resolved_reports: reportos resolvite software: Software + sources: Fontes de inscription + space: Uso de spatio + title: Pannello de controlo top_languages: Linguas le plus active top_servers: Servitores le plus active website: Sito web + disputes: + appeals: + empty: Nulle appellos trovate. + title: Appellos domain_allows: add_new: Permitter federation con dominio + created_msg: Le dominio ha essite permittite con successo pro federation + destroyed_msg: Le dominio ha essite prohibite pro federation export: Exportar import: Importar + undo: Prohiber federation con dominio domain_blocks: + add_new: Adder nove blocada de dominio confirm_suspension: cancel: Cancellar + confirm: Suspender + permanent_action: Disfacer le suspension non restaurara alcun datos o relation. + preamble_html: Tu es sur le puncto de suspender %{domain} e su subdominios. + remove_all_data: Isto removera de tu servitor tote le contento, multimedia e datos de profilo del contos de iste dominio. stop_communication: Tu servitor stoppara le communication con iste servitores. + title: Confirmar le blocada del dominio %{domain} + undo_relationships: Isto disfacera omne relation de sequimento inter le contos de iste servitores e illos del tue. + created_msg: Le blocada del dominio es ora in tractamento + destroyed_msg: Le blocada del dominio ha essite disfacite domain: Dominio - edit: Modificar un bloco de dominio + edit: Modificar un blocada de dominio + existing_domain_block: Tu ha ja imponite limites plus stricte sur %{name}. + existing_domain_block_html: Tu ha ja imponite limites plus stricte sur %{name}; ora es necessari disblocar lo primo. export: Exportar import: Importar new: + create: Crear blocada + hint: Le blocada del dominio non impedira le creation de entratas de conto in le base de datos, ma applicara retroactive- e automaticamente le methodos specific de moderation a iste contos. severity: + desc_html: "Limitar rendera le messages del contos de iste dominio invisibile pro tote persona que non los seque. Suspender removera de tu servitor tote le contento, multimedia e datos de profilo del contos de iste dominio. Usa Necun si tu solmente vole rejectar le files multimedial." + noop: Nemo silence: Limitar suspend: Suspender + title: Nove blocada de dominio + no_domain_block_selected: Necun blocada de dominio ha essite cambiate perque necun ha essite seligite + not_permitted: Tu non es autorisate a exequer iste action + obfuscate: Offuscar le nomine de dominio + obfuscate_hint: Offuscar partialmente le nomine de dominio in le lista si le diffusion del lista de limitationes del dominio es activate private_comment: Commento private + private_comment_hint: Commentar iste limitation de dominio pro uso interne per le moderatores. public_comment: Commento public + public_comment_hint: Commentar iste limitation de dominio pro le publico general, si le diffusion del lista de limitationes del dominio es activate. + reject_media: Refusar files multimedial + reject_media_hint: Remove le files multimedial immagazinate localmente e refusa de discargar tales in futuro. Irrelevante pro le suspensiones + reject_reports: Refusar reportos + reject_reports_hint: Ignorar tote le reportos proveniente de iste dominio. Irrelevante pro le suspensiones + undo: Disfacer blocada de dominio + view: Examinar blocada de dominio email_domain_blocks: add_new: Adder nove + allow_registrations_with_approval: Permitter inscriptiones con approbation + attempts_over_week: + one: "%{count} tentativa de inscription in le ultime septimana" + other: "%{count} tentativas de inscription in le ultime septimana" + created_msg: Le dominio de e-mail ha essite blocate delete: Deler + dns: + types: + mx: Registro MX domain: Dominio new: create: Adder un dominio + resolve: Resolver dominio title: Blocar un nove dominio de e-mail + no_email_domain_block_selected: Necun blocadas de dominio de e-mail ha essite cambiate perque necun ha essite seligite + not_permitted: Non permittite + resolved_dns_records_hint_html: Le nomine de dominio se resolve al sequente dominios MX, le quales ha le ultime responsibilitate pro le reception de e-mail. Blocar un dominio MX blocara le inscriptiones de qualcunque adresse de e-mail que usa le mesme dominio MX, mesmo si le nomine de dominio visibile es differente. Presta attention a evitar de blocar le grande fornitores de e-mail. + resolved_through_html: Resolvite per %{domain} title: Dominios de e-mail blocate export_domain_allows: + new: + title: Importar permissiones de dominio no_file: Necun file seligite export_domain_blocks: + import: + description_html: Tu es sur le puncto de importar un lista de blocadas de dominio. Per favor revide con grande cura iste lista, particularmente si tu non lo ha scribite tu mesme. + existing_relationships_warning: Relationes existente de sequimento + private_comment_description_html: 'Pro adjutar te a traciar de ubi proveni le blocadas importate, le blocadas importate essera create con le sequente commento private: %{comment}' + private_comment_template: Importate de %{source} le %{date} + title: Importar blocadas de dominio + invalid_domain_block: 'Un o plus blocadas de dominio ha essite saltate a causa del sequente error(es): %{error}' + new: + title: Importar blocadas de dominio no_file: Necun file seligite follow_recommendations: + description_html: "Le recommendationes de sequimento adjuta le nove usatores a trovar rapidemente contento interessante. Quando un usator non ha un historia sufficiente de interactiones con alteres pro formar recommendationes personalisate de sequimento, iste contos es recommendate. Illos se recalcula cata die a partir de un mixtura de contos con le plus grande numero de ingagiamentos recente e le numero de sequitores local le plus alte pro un lingua date." language: Per lingua status: Stato + suppress: Supprimer recommendation de sequimento + suppressed: Supprimite title: Sequer le recommendationes + unsuppress: Restaurar recommendation de sequimento instances: + availability: + description_html: + one: Si le livration al dominio falle %{count} die sin succeder, necun tentativa ulterior de livration essera facite, excepte si es recipite un livration ab le dominio. + other: Si le livration al dominio falle durante %{count} dies differente sin succeder, necun tentativa ulterior de livration essera facite, excepte si es recipite un livration ab le dominio. + failure_threshold_reached: Limine de fallimentos attingite le %{date}. + failures_recorded: + one: Tentativa fallite durante %{count} die. + other: Tentativa fallite durante %{count} dies differente. + no_failures_recorded: Necun fallimento cognoscite. + title: Disponibilitate + warning: Le ultime tentativa de connexion a iste servitor non ha succedite back_to_all: Toto back_to_limited: Limitate back_to_warning: Advertimento by_domain: Dominio + confirm_purge: Es tu secur que tu vole deler permanentemente le datos de iste dominio? content_policies: comment: Nota interne + description_html: Tu pote definir politicas de contento que se applicara a tote le contos de iste dominio e a qualcunque de su subdominios. + limited_federation_mode_description_html: Tu pote decider si permitter le federation con iste dominio. policies: + reject_media: Rejectar multimedia + reject_reports: Rejectar reportos silence: Limitar suspend: Suspender policy: Politica reason: Ration public + title: Politicas de contento dashboard: instance_accounts_dimension: Contos le plus sequite + instance_accounts_measure: contos immagazinate + instance_followers_measure: nostre sequitores illac + instance_follows_measure: lor sequitores hic instance_languages_dimension: Linguas principal + instance_media_attachments_measure: annexos multimedial immagazinate + instance_reports_measure: signalationes sur illos + instance_statuses_measure: messages immagazinate delivery: + all: Totes + clear: Rader errores de livration + failing: Fallente + restart: Recomenciar livration + stop: Cessar livration unavailable: Non disponibile + delivery_available: Livration es disponibile + delivery_error_days: Dies de errores de livration + delivery_error_hint: Si le livration non es possibile durante %{count} dies, illo essera automaticamente marcate como non livrabile. + destroyed_msg: Le datos de %{domain} es ora in cauda pro deletion imminente. empty: Necun dominios trovate. + known_accounts: + one: "%{count} conto cognoscite" + other: "%{count} contos cognoscite" moderation: all: Toto limited: Limitate title: Moderation private_comment: Commento private public_comment: Commento public + purge: Purgar + purge_description_html: Si tu crede que iste dominio es foras de linea pro sempre, tu pote deler de tu immagazinage tote le registros del conto e le datos associate de iste dominio. Isto pote prender un tempore. title: Federation total_blocked_by_us: Blocate per nos + total_followed_by_them: Sequite per illes total_followed_by_us: Sequite per nos + total_reported: Signalationes sur illes + total_storage: Annexos multimedial + totals_time_period_hint_html: Le totales monstrate hic infra include le datos de tote le tempore. + unknown_instance: Iste dominio non es actualmente cognoscite sur iste servitor. invites: deactivate_all: Disactivar toto filter: @@ -357,6 +534,7 @@ ia: title: Invitationes ip_blocks: add_new: Crear regula + created_msg: Le nove regula IP ha essite addite delete: Deler expires_in: '1209600': 2 septimanas @@ -367,8 +545,12 @@ ia: '94670856': 3 annos new: title: Crear un nove regula IP + no_ip_block_selected: Necun regula IP ha essite cambiate perque necun ha essite seligite title: Regulas IP + relationships: + title: Relationes de %{acct} relays: + add_new: Adder nove repetitor delete: Deler description_html: Un repetitor de federation es un servitor intermediari que excambia grande volumines de messages public inter le servitores que se inscribe e publica a illo. Illo pote adjutar le servitores micre e medie a discoperir le contento del fediverso, sin requirer que le usatores local seque manualmente altere personas sur servitores distante. disable: Disactivar @@ -376,59 +558,212 @@ ia: enable: Activar enable_hint: Un vice activate, tu servitor se inscribera a tote le messages public de iste repetitor, e comenciara a inviar le messages public de iste servitor a illo. enabled: Activate + inbox_url: URL del repetitor + pending: Attende le approbation del repetitor save_and_enable: Salveguardar e activar + setup: Crear un connexion con un repetitor + signatures_not_enabled: Le repetitores pote non functionar correctemente durante que le modo secur o le modo de federation limitate es activate status: Stato + title: Repetitores + report_notes: + created_msg: Nota de signalation create con successo! + destroyed_msg: Nota de signalation delite con successo! reports: + account: + notes: + one: "%{count} nota" + other: "%{count} notas" + action_log: Registro de inspection + action_taken_by: Action prendite per + actions: + delete_description_html: Le messages signalate essera delite e un admonition essera registrate pro adjutar te a prender mesuras in caso de futur infractiones proveniente del mesme conto. + mark_as_sensitive_description_html: Le files multimedial in le messages reportate essera marcate como sensibile e un admonition essera registrate pro adjutar te a prender mesuras in caso de futur infractiones proveniente del mesme conto. + other_description_html: Vider plus optiones pro controlar le comportamento del conto e personalisar le communication al conto signalate. + resolve_description_html: Necun action essera prendite contra le conto signalate, necun admonition registrate, e le signalation essera claudite. + silence_description_html: Iste conto essera visibile solmente a qui ja lo seque o manualmente lo cerca, limitante gravemente su portata. Pote sempre esser revertite. Claude tote le signalationes contra iste conto. + suspend_description_html: Le conto e tote su contento essera inaccessible e finalmente delite, e interager con illo essera impossibile. Reversibile intra 30 dies. Claude tote le signalationes contra iste conto. + actions_description_html: Decide qual action prender pro resolver iste signalation. Si tu prende un action punitive contra le conto signalate, le persona recipera un notification in e-mail, excepte si le categoria Spam es seligite. + actions_description_remote_html: Decide qual action prender pro resolver iste signalation. Isto affectara solmente le maniera in que tu servitor communica con iste conto remote e gere su contento. add_to_report: Adder plus al reporto + already_suspended_badges: + local: Ja suspendite sur iste servitor + remote: Ja suspendite sur su servitor are_you_sure: Es tu secur? + assign_to_self: Assignar a me + assigned: Moderator assignate + by_target_domain: Dominio del conto signalate cancel: Cancellar category: Categoria + category_description_html: Le motivo pro le qual iste conto e/o contento ha essite signalate essera citate in le communication con le conto signalate + comment: + none: Necun + comment_description_html: 'Pro fornir plus information, %{name} ha scribite:' confirm: Confirmar + confirm_action: Confirmar le action de moderation contra %{acct} + created_at: Signalate delete_and_resolve: Deler le messages + forwarded: Reexpedite + forwarded_replies_explanation: Iste signalation proveni de un usator remote e concerne contento remote. Illo te ha essite reexpedite perque le contento signalate es in responsa a un usator tue. + forwarded_to: Reexpedite a %{domain} + mark_as_resolved: Marcar como resolvite + mark_as_sensitive: Marcar como sensibile + mark_as_unresolved: Marcar como non resolvite no_one_assigned: Nemo notes: create: Adder un nota + create_and_resolve: Resolver con nota + create_and_unresolve: Reaperir con nota delete: Deler + placeholder: Describe le actiones prendite, o insere altere information pertinente... title: Notas + notes_description_html: Vider e lassar notas pro altere moderatores e pro tu proprie futuro + processed_msg: 'Reporto #%{id} elaborate con successo' + quick_actions_description_html: 'Face un rapide action o rola a basso pro vider le contento reportate:' + remote_user_placeholder: le usator remote ab %{instance} + reopen: Reaperir reporto + report: 'Reporto #%{id}' + reported_account: Conto signalate + reported_by: Signalate per + resolved: Resolvite + resolved_msg: Reporto resolvite con successo! skip_to_actions: Saltar al actiones status: Stato + statuses: Contento signalate + statuses_description_html: Le contento offensive sera citate in communication con le conto reportate + summary: + action_preambles: + delete_html: 'Tu va remover parte de messages de @%{acct}. Isto ira:' + mark_as_sensitive_html: 'Tu va marcar parte de messages de @%{acct} como sensibile. Isto ira:' + silence_html: 'Tu va limitar le conto de @%{acct}. Isto ira:' + suspend_html: 'Tu va limitar le conto de @%{acct}. Isto ira:' + actions: + delete_html: Remover le messages offensive + mark_as_sensitive_html: Marcar le medios de messages offensive como sensibile + silence_html: Limitar gravemente le portata de @%{acct} rendente le profilo e contento visibile solmente a qui ja lo seque o lo cerca manualmente + suspend_html: Suspender @%{acct}, rendente le profilo e contento inaccessibile e le interaction con illo impossibile + close_report: Marcar le signalation №%{id} como resolvite + close_reports_html: Marcar tote le signalationes contra @%{acct} como resolvite + delete_data_html: Deler le profilo e contento de @%{acct} in 30 dies excepte si le suspension es disfacite intertanto + preview_preamble_html: "@%{acct} recipera un advertimento con le sequente contento:" + record_strike_html: Registrar un admonition contra @%{acct} pro adjutar te a imponer sanctiones in caso de futur violationes de iste conto + send_email_html: Inviar un e-mail de advertimento a @%{acct} + warning_placeholder: Motivation supplementari facultative pro le action de moderation. + target_origin: Origine del conto signalate + title: Reportos + unassign: Disassignar + unknown_action_msg: 'Action incognite: %{action}' + unresolved: Non resolvite updated_at: Actualisate view_profile: Vider profilo roles: + add_new: Adder rolo assigned_users: one: "%{count} usator" other: "%{count} usatores" categories: + administration: Administration + devops: DevOps invites: Invitationes moderation: Moderation special: Special delete: Deler + description_html: Le rolos de usator permitte personalisar le functiones e areas de Mastodon al quales le usator pote acceder. + edit: Modificar le rolo '%{name}' everyone: Permissiones predefinite + everyone_full_description_html: Iste es le rolo de base que affecta tote le usatores, mesmo illes sin rolo assignate. Tote le altere rolos heredita le permissiones de illo. + permissions_count: + one: "%{count} permission" + other: "%{count} permissiones" privileges: + administrator: Administrator + administrator_description: Le usatores con iste permission pote contornar tote permission delete_user_data: Deler le datos de usator + delete_user_data_description: Permitte que usatores dele immediatemente le datos de altere usatores + invite_users: Invitar usatores + invite_users_description: Permitte que usatores invita nove personas al servitor manage_announcements: Gerer le annuncios + manage_announcements_description: Permitte que usatores genere annuncios sur le servitor + manage_appeals: Gerer appellos + manage_appeals_description: Permitte que usatores revide appellos contra actiones de moderation + manage_blocks: Gerer blocadas + manage_blocks_description: Permitter que usatores bloca le fornitores de e-mail e le adresses IP + manage_custom_emojis: Gerer emojis personalisate + manage_custom_emojis_description: Permitte que usatores gere emojis personalisate sur le servitor + manage_federation: Gerer federation + manage_federation_description: Permitte que le usatores bloca o permitte le federation con altere dominios, e controla le livration manage_invites: Gerer le invitationes + manage_invites_description: Permitte que usatores examina e deactiva ligamines de invitation + manage_reports: Gerer le reportos + manage_reports_description: Permitte que usatores revide signalationes e exeque actiones de moderation a base de illos + manage_roles: Gerer le rolos + manage_roles_description: Permitte que usatores gere e assigna rolos inferior a lor privilegios actual manage_rules: Gerer le regulas + manage_rules_description: Permitte que usatores cambia le regulas del servitor manage_settings: Gerer le parametros + manage_settings_description: Permitte que usatores cambia le parametros del sito + manage_taxonomies: Gerer taxonomias + manage_taxonomies_description: Permitte que usatores revide contento in tendentias e actualisa le parametros de hashtag + manage_user_access: Gerer le accessos de usator + manage_user_access_description: Permitte que usatores disactiva le authentication bifactorial de altere usatores, cambia lor adresses de e-mail, e reinitialisa lor contrasigno manage_users: Gerer usatores + manage_users_description: Permitte que usatores vide le detalios de altere usatores e exeque actiones de moderation contra illes + manage_webhooks: Gerer Webhooks + manage_webhooks_description: Permitte que usatores installa “webhooks” pro eventos administrative + view_audit_log: Vider le registro de inspection + view_audit_log_description: Permitte que usatores vide un historia de actiones administrative sur le servitor + view_dashboard: Vider le tabuliero de instrumentos + view_dashboard_description: Permitte que usatores accede al tabuliero de instrumentos e a varie statisticas + view_devops: DevOps + view_devops_description: Permitte que usatores accede al tabulieros de instrumentos de Sidekiq e pgHero title: Rolos rules: + add_new: Adder regula delete: Deler + description_html: Ben que multes affirma de haber legite e acceptate le conditiones de servicio, generalmente le gente non los lege completemente usque un problema surge. Facilita le visibilitate del regulas de tu servitor in un colpo de oculo forniente los in un lista a punctos. Tenta mantener le regulas individual curte e simple, ma sin divider los in multe punctos separate. + edit: Modificar regula + empty: Necun regula del servitor ha essite definite ancora. + title: Regulas del servitor settings: about: + manage_rules: Gerer le regulas del servitor + preamble: Fornir information detaliate sur le functionamento, moderation e financiamento del servitor. + rules_hint: Il ha un area dedicate al regulas que tu usatores debe acceptar. title: A proposito de appearance: preamble: Personalisar le interfacie web de Mastodon. title: Apparentia + branding: + preamble: Le marca de tu servitor lo differentia de altere servitores in le rete. Iste information pote esser monstrate in diverse ambientes, como le interfacie web de Mastodon, applicationes native, in previsualisationes de ligamines sur altere sitos web, in applicationes de messageria, etc. Pro iste ration, il es melior mantener iste information clar, breve e concise. + title: Marca + captcha_enabled: + desc_html: Iste depende de scripts externe de hCaptcha, que pote esser un problema de securitate e vita private. De plus, isto pote render le processo de inscription multo minus accessibile a certe personas (particularmente personas con discapacitates). Pro iste rationes, considera altere mesuras como le inscription basate sur approbation o invitation. + title: Require que nove usatores solve un CAPTCHA pro confirmar lor conto + content_retention: + danger_zone: Zona periculose discovery: profile_directory: Directorio de profilos public_timelines: Chronologias public + title: Discoperi trends: Tendentias + domain_blocks: + all: A omnes + disabled: A necuno + users: A usators local in session + registrations: + title: Registrationes + registrations_mode: + modes: + none: Nemo pote inscriber se + open: Quicunque pote inscriber se + security: + authorized_fetch_hint: Requirer authentication de servitores federate permitte un application plus stricte de blocadas a nivello de usator e de servitor. Nonobstante, isto diminue le prestationes del servitor, reduce le portata de tu responsas e pote introducer problemas de compatibilitate con certe servicios federate. In plus, isto non impedira le actores dedicate a recuperar tu messages public e tu contos. title: Parametros de servitor site_uploads: delete: Deler file incargate + destroyed_msg: Incarga de sito delite con successo! software_updates: documentation_link: Pro saper plus + release_notes: Notas de version title: Actualisationes disponibile type: Typo types: @@ -443,31 +778,136 @@ ia: deleted: Delite favourites: Favoritos history: Chronologia del versiones + in_reply_to: Replicante a language: Lingua media: title: Medios metadata: Metadatos open: Aperir message original_status: Message original + status_changed: Messages cambiate title: Messages del conto trending: Tendentias visibility: Visibilitate + with_media: Con medios strikes: actions: + delete_statuses: "%{name} ha delite le messages de %{target}" + disable: "%{name} ha gelate le conto de %{target}" + mark_statuses_as_sensitive: "%{name} ha marcate le messages de %{target} como sensibile" none: "%{name} ha inviate un advertimento a %{target}" + sensitive: "%{name} ha marcate le conto de %{target} como sensibile" + silence: "%{name} ha limitate le conto de %{target}" + suspend: "%{name} ha suspendite le conto de %{target}" + appeal_approved: Appello facite + appeal_pending: Appello pendente + appeal_rejected: Appello rejectate system_checks: + elasticsearch_preset: + action: Vide documentation + elasticsearch_preset_single_node: + action: Vide documentation rules_check: action: Gerer le regulas del servitor software_version_critical_check: action: Vider le actualisationes disponibile + message_html: Un actualisation critic de Mastodon es disponibile, actualisa lo le plus rapide possibile. software_version_patch_check: action: Vider le actualisationes disponibile upload_check_privacy_error: action: Verifica hic pro plus de information + upload_check_privacy_error_object_storage: + action: Verifica hic pro plus de information + trends: + approved: Approbate + rejected: Rejectate + tags: + not_usable: Non pote esser usate + title: Tendentias + warning_presets: + add_new: Adder nove + delete: Deler + webhooks: + delete: Deler + disable: Disactivar + disabled: Disactivate + enable: Activar + events: Eventos + status: Stato + admin_mailer: + new_critical_software_updates: + subject: Actualisationes critic de Mastodon es disponibile pro %{instance}! + new_software_updates: + subject: Nove versiones de Mastodon es disponibile pro %{instance}! + appearance: + advanced_web_interface: Interfacie web avantiate + sensitive_content: Contento sensibile application_mailer: + notification_preferences: Cambiar preferentias de e-mail + settings: 'Cambiar preferentias de e-mail: %{link}' unsubscribe: Desubscriber + view: 'Vider:' + view_profile: Vider profilo + view_status: Vider message + applications: + created: Application create con successo + destroyed: Application delite con successo + logout: Clauder le session + auth: + confirmations: + welcome_title: Benvenite, %{name}! + delete_account: Deler le conto + logout: Clauder le session + progress: + details: Tu detalios + set_new_password: Definir un nove contrasigno + status: + account_status: Stato del conto + view_strikes: Examinar le admonitiones passate contra tu conto + challenge: + invalid_password: Contrasigno non valide + deletes: + proceed: Deler le conto + success_msg: Tu conto esseva delite con successo + warning: + data_removal: Tu messages e altere datos essera removite permanentemente + email_change_html: Tu pote cambiar tu adresse de e-mail sin deler tu conto + disputes: + strikes: + action_taken: Action prendite + appeal: Facer appello + appeal_approved: Iste admonition ha essite annullate in appello e non es plus valide + appeal_rejected: Le appello ha essite rejectate + appeal_submitted_at: Appello submittite + appealed_msg: Tu appello ha essite submittite. Si es approbate, tu recipera notification. + appeals: + submit: Submitter appello + approve_appeal: Approbar apello + associated_report: Signalation associate + created_at: Del data + description_html: Istes es le actiones prendite contra tu conto e le advertimentos que te ha essite inviate per le personal de %{instance}. + recipient: Adressate a + reject_appeal: Rejectar appello + status: Message №%{id} + status_removed: Le message ha ja essite removite del systema + title: "%{action} del %{date}" + title_actions: + delete_statuses: Elimination de messages + disable: Gelamento del conto + mark_statuses_as_sensitive: Marcation de messages como sensibile + none: Advertimento + sensitive: Marcation del conto como sensibile + silence: Limitation del conto + suspend: Suspension del conto + your_appeal_approved: Tu appello ha essite approbate + your_appeal_pending: Tu ha submittite un appello + your_appeal_rejected: Tu appello ha essite rejectate edit_profile: + basic_information: Information basic other: Alteres + errors: + '422': + content: Le verification de securitate ha fallite. Bloca tu le cookies? existing_username_validator: not_found_multiple: non poteva trovar %{usernames} exports: @@ -478,6 +918,7 @@ ia: blocks: Tu ha blocate bookmarks: Marcapaginas csv: CSV + domain_blocks: Blocadas de dominio mutes: Tu ha silentiate storage: Immagazinage de medios featured_tags: @@ -496,6 +937,10 @@ ia: title: Modificar filtro index: delete: Deler + title: Filtros + new: + save: Salveguardar nove filtro + title: Adder nove filtro generic: all: Toto cancel: Cancellar @@ -509,12 +954,37 @@ ia: imports: errors: empty: File CSV vacue + invalid_csv_file: 'File CSV non valide. Error: %{error}' too_large: Le file es troppo longe failures: Fallimentos + overwrite_preambles: + blocking_html: Tu es sur le puncto de reimplaciar tu lista de blocadas per usque a %{total_items} contos proveniente de %{filename}. + domain_blocking_html: Tu es sur le puncto de reimplaciar tu lista de blocadas de dominio per usque a %{total_items} dominios proveniente de %{filename}. + preambles: + blocking_html: Tu es sur le puncto de blocar usque a %{total_items} contos a partir de %{filename}. + domain_blocking_html: Tu es sur le puncto de blocar usque a %{total_items} dominios a partir de %{filename}. + preface: Tu pote importar datos que tu ha exportate de un altere servitor, como un lista de personas que tu seque o bloca. + recent_imports: Importationes recente status: Stato + titles: + blocking: Importation de contos blocate + bookmarks: Importation de marcapaginas + domain_blocking: Importation de dominios blocate + lists: Importation de listas + muting: Importation de contos silentiate + type: Typo de importation + type_groups: + constructive: Sequites e marcapaginas + destructive: Blocadas e silentiamentos types: + blocking: Lista de blocadas + bookmarks: Marcapaginas + domain_blocking: Lista de dominios blocate lists: Listas + upload: Incargar invites: + delete: Disactivar + expired: Expirate expires_in: '1800': 30 minutas '21600': 6 horas @@ -544,9 +1014,90 @@ ia: migrations: errors: not_found: non poterea esser trovate + move_handler: + carry_blocks_over_text: Iste usator ha cambiate de conto desde %{acct}, que tu habeva blocate. + notification_mailer: + follow: + title: Nove sequitor + follow_request: + title: Nove requesta de sequimento + mention: + action: Responder + poll: + subject: Un inquesta de %{name} ha finite + pagination: + next: Sequente preferences: + other: Altere public_timelines: Chronologias public + privacy_policy: + title: Politica de confidentialitate + relationships: + activity: Activitate del conto + most_recent: Plus recente + status: Stato del conto + sessions: + activity: Ultime activitate + browser: Navigator + browsers: + alipay: Alipay + blackberry: BlackBerry + chrome: Chrome + edge: Microsoft Edge + electron: Electron + firefox: Firefox + generic: Navigator incognite + huawei_browser: Huawei Browser + ie: Internet Explorer + micro_messenger: MicroMessenger + nokia: Navigator de Nokia S40 Ovi + opera: Opera + otter: Otter + phantom_js: PhantomJS + qq: QQ Browser + safari: Safari + uc_browser: UC Browser + unknown_browser: Navigator Incognite + weibo: Weibo + current_session: Session actual + date: Data + description: "%{browser} sur %{platform}" + 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 + unknown_platform: Platteforma incognite + windows: Windows + windows_mobile: Windows Mobile + windows_phone: Windows Phone + settings: + account: Conto + account_settings: Parametros de conto + appearance: Apparentia + delete: Deletion de conto + development: Disveloppamento + edit_profile: Modificar profilo + import: Importar + migrate: Migration de conto + notifications: Notificationes de e-mail + preferences: Preferentias + profile: Profilo public + relationships: Sequites e sequitores + strikes: Admonitiones de moderation + severed_relationships: + event_type: + domain_block: Suspension del servitor (%{target_name}) + user_domain_block: Tu ha blocate %{target_name} + preamble: Tu pote perder sequites e sequitores quando tu bloca un dominio o quando tu moderatores decide suspender un servitor remote. Quando isto occurre, tu potera discargar listas de relationes rumpite, a inspectar e eventualmente importar in un altere servitor. + type: Evento statuses: + open_in_web: Aperir in le web poll: vote: Votar show_more: Monstrar plus @@ -563,7 +1114,13 @@ ia: '604800': 1 septimana '63113904': 2 annos '7889238': 3 menses + stream_entries: + sensitive_content: Contento sensibile + strikes: + errors: + too_late: Es troppo tarde pro facer appello contra iste admonition themes: + contrast: Mastodon (Alte contrasto) default: Mastodon (Obscur) mastodon-light: Mastodon (Clar) system: Automatic (usar thema del systema) @@ -574,6 +1131,24 @@ ia: user_mailer: appeal_approved: action: Parametros de conto + explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite approbate. Tu conto ha de novo un bon reputation. + appeal_rejected: + explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite rejectate. + warning: + appeal: Submitter un appello + subject: + none: Advertimento pro %{acct} + sensitive: Tu messages sur %{acct} essera marcate como sensibile a partir de ora + silence: Tu conto %{acct} ha essite limitate + suspend: Tu conto %{acct} ha essite suspendite + title: + delete_statuses: Messages removite + disable: Conto gelate + mark_statuses_as_sensitive: Messages marcate como sensibile + none: Advertimento + sensitive: Conto marcate como sensibile + silence: Conto limitate + suspend: Conto suspendite welcome: apps_android_action: Obtene lo sur Google Play apps_ios_action: Discargar sur le App Store @@ -582,6 +1157,9 @@ ia: edit_profile_action: Personalisar edit_profile_title: Personalisar tu profilo feature_action: Apprender plus + follow_action: Sequer + post_title: Face tu prime message + share_action: Compartir share_title: Compartir tu profilo de Mastodon subject: Benvenite in Mastodon verification: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index da9a421411..0712ba380a 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -737,6 +737,7 @@ ja: desc_html: この機能は hCaptcha による外部スクリプトを使用しますが、hCaptcha にはセキュリティとプライバシーの懸念が考えられます。また、CAPTCHAにより新規登録のアクセシビリティが大幅に損なわれる可能性があり、身体および精神障害者においては特に顕著です。以上の理由から、承認制や招待制を基本とするなど、代わりの登録手順を提供することを検討してください。 title: 新規ユーザーのアカウント確認にCHAPCHAを要求する content_retention: + danger_zone: 危険な操作 preamble: ユーザーが生成したコンテンツがどのように Mastodon に保存されるかを管理します。 title: コンテンツの保持 default_noindex: diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 82fbde6ce1..3449f1d5d7 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -410,6 +410,8 @@ lt: silence: Riboti suspend: Pristabdyti title: Naujos domeno blokas + public_comment: Viešas komentaras + public_comment_hint: Komentaras apie šį domeno apribojimą plačiajai visuomenei, jei įjungtas domenų apribojimų sąrašo reklamavimas. reject_media: Atmesti medijos failus reject_media_hint: Panaikina lokaliai saugomus medijos failus bei atsisako jų parsisiuntimo ateityje. Neliečia užblokavimu reject_reports: Atmesti ataskaitas @@ -427,11 +429,14 @@ lt: title: El pašto juodasis sąrašas instances: by_domain: Domenas + content_policies: + reason: Viešoji priežastis delivery_available: Pristatymas galimas moderation: all: Visi limited: Limituotas title: Moderacija + public_comment: Viešas komentaras title: Federacija total_blocked_by_us: Mes užblokavome total_followed_by_them: Jų sekami @@ -449,11 +454,11 @@ lt: relays: add_new: Pridėti naują pamainą delete: Ištrinti - description_html: "Federacijos perjungėjas tai tarpinis serveris, kuris apsikeičia didelios apimties informacija tarp kitų serverių. Tai gali padėti mažesniems serveriams atrasti turinį iš fedi-visatos, kuris kitaip reikalautų vartotojų lokaliai sekti kitus žmones naudojantis kitus tolimus serverius." + description_html: "Federacijos perdavimas – tai tarpinis serveris, kuris keičiasi dideliais viešų įrašų kiekiais tarp jį prenumeruojančių ir skelbiančių serverių. Jis gali padėti mažiems ir vidutiniams serveriams atrasti fediverse esantį turinį, nes priešingu atveju vietiniams naudotojams reikėtų rankiniu būdu sekti kitus žmones iš nutolusių serverių." disable: Išjungti disabled: Išjungtas enable: Įjungti - enable_hint: Kai įjungta, Jūsų serveris prenumeruos visas viešas žinutes iš šio tinklo, ir pradės siųsti šio serverio viešas žinutes į tinklą. + enable_hint: Kai bus įjungtas, tavo serveris užsiprenumeruos visus šio perdavimo viešus įrašus ir pradės į jį siųsti šio serverio viešus įrašus. enabled: Įjungtas inbox_url: Perdavimo URL pending: Laukiama perdavimo patvirtinimo @@ -504,6 +509,8 @@ lt: desc_html: Tai priklauso nuo hCaptcha išorinių skriptų, kurie gali kelti susirūpinimą dėl saugumo ir privatumo. Be to, dėl to registracijos procesas kai kuriems žmonėms (ypač neįgaliesiems) gali būti gerokai sunkiau prieinami. Dėl šių priežasčių apsvarstyk alternatyvias priemones, pavyzdžiui, patvirtinimu arba kvietimu grindžiamą registraciją. content_retention: danger_zone: Pavojinga zona + discovery: + public_timelines: Viešieji laiko skalės domain_blocks: all: Visiems registrations: @@ -543,7 +550,7 @@ lt: body: Mastodon verčia savanoriai. guide_link_text: Visi gali prisidėti. application_mailer: - notification_preferences: Keisti el pašto parinktis + notification_preferences: Keisti el. pašto nuostatas settings: 'Keisti el. pašto nuostatas: %{link}' view: 'Peržiūra:' view_profile: Peržiurėti profilį @@ -635,7 +642,7 @@ lt: contexts: home: Namų laiko juosta notifications: Priminimai - public: Viešos laiko juostos + public: Viešieji laiko skalės thread: Pokalbiai edit: title: Keisti filtrą @@ -727,6 +734,8 @@ lt: prev: Ankstesnis preferences: other: Kita + posting_defaults: Skelbimo numatytosios nuostatos + public_timelines: Viešieji laiko skalės privacy: hint_html: "Tikrink, kaip nori, kad tavo profilis ir įrašai būtų randami. Įjungus įvairias Mastodon funkcijas, jos gali padėti pasiekti platesnę auditoriją. Akimirką peržiūrėk šiuos nustatymus, kad įsitikintum, jog jie atitinka tavo naudojimo būdą." redirects: @@ -769,7 +778,8 @@ lt: import: Importuoti migrate: Paskyros migracija notifications: El. laiško pranešimai - preferences: Preferencijos + preferences: Nuostatos + profile: Viešas profilis two_factor_authentication: Dviejų veiksnių autentikacija statuses: attached: diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 8e30a27b8b..0c2e6cfd6d 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -751,6 +751,7 @@ pt-PT: desc_html: Isto depende de scripts externos da hCaptcha, o que pode ser uma preocupação de segurança e privacidade. Além disso, isto pode tornar o processo de registo menos acessível para algumas pessoas (especialmente as com limitações físicas). Por isso, considere medidas alternativas tais como registo mediante aprovação ou sob convite. title: Requerer que novos utilizadores resolvam um CAPTCHA para confirmar a sua conta content_retention: + danger_zone: Zona de perigo preamble: Controle como o conteúdo gerado pelos utilizadores é armazenado no Mastodon. title: Retenção de conteúdo default_noindex: diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml index 29e525b2c8..a1406b1ad9 100644 --- a/config/locales/simple_form.ar.yml +++ b/config/locales/simple_form.ar.yml @@ -240,6 +240,7 @@ ar: backups_retention_period: فترة الاحتفاظ بأرشيف المستخدم bootstrap_timeline_accounts: أوصي دائما بهذه الحسابات للمستخدمين الجدد closed_registrations_message: رسالة مخصصة عندما يكون التسجيل غير متاح + content_cache_retention_period: مدة الاحتفاظ بالمحتوى البعيد custom_css: سي أس أس CSS مخصص mascot: جالب حظ مخصص (قديم) media_cache_retention_period: مدة الاحتفاظ بالتخزين المؤقت للوسائط diff --git a/config/locales/simple_form.he.yml b/config/locales/simple_form.he.yml index b07ed8b8b5..841745dbc0 100644 --- a/config/locales/simple_form.he.yml +++ b/config/locales/simple_form.he.yml @@ -77,10 +77,13 @@ he: warn: הסתר את התוכן המסונן מאחורי אזהרה עם כותרת המסנן form_admin_settings: activity_api_enabled: מספר ההודעות שפורסמו מקומית, משתמשים פעילים, והרשמות חדשות בדליים שבועיים + backups_retention_period: למשתמשים יש יכולת לבקש ארכיון של הודעותיהם להורדה מאוחר יותר. כאשר נבחר ערך חיובי, הארכיונים הללו ימחקו מאחסון לאחר מספר הימים שצוינו. bootstrap_timeline_accounts: חשבונות אלו יוצמדו לראש רשימת המלצות המעקב של משתמשים חדשים. closed_registrations_message: להציג כאשר הרשמות חדשות אינן מאופשרות + content_cache_retention_period: כל ההודעות משרתים אחרים (לרבות הדהודים ותגובות) ימחקו אחרי מספר ימים, ללא קשר לאינטראקציה של משתמשים מקומיים איתם. בכלל זה הודעות שהמתשתמשים המקומיים סימנו בסימניה או חיבוב. איזכורים פרטיים ("דיאם") בין משתמשים בין שרתים שונים יאבדו גם הם ולא תהיה אפשרות לשחזרם. השימוש באפשרות הזו מיועד לשרתים עם ייעוד מיוחד ושובר את ציפיותיהם של רב המשתמשים כאשר האפשרות מופעלת בשרת לשימוש כללי. custom_css: ניתן לבחור ערכות סגנון אישיות בגרסת הדפדפן של מסטודון. mascot: בחירת ציור למנשק הווב המתקדם. + media_cache_retention_period: קבצי מדיה מהודעות שהגיעו משרתים רחוקים נשמרות על השרת שלך. כאשר יבחר פה מספר חיובי, המדיה תמחק לאחר מספר ימים כמצוין. אם המידע יבוקש שוב לאחר שנמחק, הוא יורד מחדש, אם המידע עדיין זמין בצד הרחוק. עקב מגבלות על תכיפות שליפת כרטיסי קדימון מאתרים מרוחקים, מומלץ לכוון את הערך ל־14 יום לפחות, או שכרטיסי קדימונים לא יעודכנו לפי דרישה לפני חלוף חלון הזמן הזה. peers_api_enabled: רשימת השרתים ששרת זה פגש בפדיוורס. לא כולל מידע לגבי קשר ישיר עם שרת נתון, אלא רק שידוע לשרת זה על קיומו. מידע זה משמש שירותים האוספים סטטיסטיקות כלליות על הפדרציה. profile_directory: ספריית הפרופילים מציגה ברשימה את כל המשתמשים שביקשו להיות ניתנים לגילוי. require_invite_text: כאשר הרשמות דורשות אישור ידני, הפיכת טקסט ה"מדוע את/ה רוצה להצטרף" להכרחי במקום אופציונלי diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index b5ec14e60e..c796cb5fac 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -90,11 +90,54 @@ ia: site_contact_email: Como pote contactar te le personas pro questiones legal o de supporto. site_contact_username: Como pote contactar te le personas re Mastodon. site_extended_description: Qualcunque information additional que pote esser utile al visitatores e a tu usatores. Pote esser structurate con syntaxe de markdown. + site_short_description: Un breve description pro adjutar a univocamente identificar tu servitor. Qui ha exequite illo, proque es illo? + site_terms: Usa tu proprie politica de confidentialitate o lassa blanc pro usar le predefinite. Pote esser structurate con syntaxe de markdown. + site_title: Como le personas pote referer se a tu servitor in addition su nomine de dominio. + status_page_url: URL de un pagina ubi le personas pote vider le stato de iste servitor durante un interruption + theme: Thema que le visitatores disconnexe e le nove usatores vide. + thumbnail: Un imagine approximativemente 2:1 monstrate al latere del informationes de tu servitor. + timeline_preview: Le visitatores disconnexe potera navigar per le plus recente messages public disponibile sur le servitor. + trendable_by_default: Saltar le revision manual del contento de tendentia. Elementos singule pote ancora esser removite de tendentias post le facto. + trends: Tendentias monstra que messages, hashtags e novas gania traction sur tu servitor. + trends_as_landing_page: Monstrar contento de tendentia a usatores disconnexe e visitatores in vice que un description de iste servitor. Require tendentias esser activate. + form_challenge: + current_password: Tu entra in un area secur + imports: + data: File CSV exportate ab un altere servitor de Mastodon + invite_request: + text: Isto nos adjutara a revider tu application ip_block: + comment: Optional. Memorar perque tu ha addite iste regula. + expires_in: Le adresses IP es un ressource finite, illos es aliquando compartite e sovente cambia manos. Pro iste ration, blocadas de IP indefinite non es recommendate. + ip: Inserer un adresse IPv4 o IPv6. Tu pote blocar campos integre per le syntaxe CIDR. Sia attente pro non disconnecter te! severities: no_access: Blocar accesso a tote le ressources + sign_up_block: Nove inscriptiones non sera possibile + sign_up_requires_approval: Nove inscriptiones requirera tu approbation + severity: Seliger que evenira con requestas ab iste IP + rule: + hint: Optional. Forni altere detalios re le regula + text: Describe un regula o requisito pro usatores sur iste servitor. Tenta de mantener lo breve e simple + sessions: + otp: 'Insere le codice a duo factores generate per le app de tu telephono o usa un de tu codices de recuperation:' + webauthn: Si illo es un clave USB cura de inserer lo e, si necessari, tocca lo. + settings: + indexable: Tu pagina del profilo pote apparer in resultatos del recerca sur Google, Bing, e alteros. + show_application: Tu sempre sera capace totevia de vider que app publicava tu message. + tag: + name: Tu pote solo cambiar le inveloppe del litteras, per exemplo, pro render lo plus legibile + user: + chosen_languages: Si marcate, solo le messages in le linguas seligite sera monstrate in chronologias public + role: Le rolo controla que permissos ha le usator + user_role: + color: Color a esser usate pro le rolo in omne parte del UI, como RGB in formato hexadecimal + highlighted: Iste rende le rolo publicamente visibile + name: Nomine public del rolo, si rolo es definite a esser monstrate como insignia + permissions_as_keys: Usatores con iste rolo habera accesso a... + position: Rolo superior decide resolution de conflicto in certe situationes. Certe actiones pote solo esser exequite sur rolos con un prioritate inferior webhook: events: Selige le eventos a inviar + template: Compone tu proprie carga utile JSON per interpolation de variabile. Lassar blanc pro JSON predefinite. url: Ubi le eventos essera inviate labels: account: @@ -105,10 +148,15 @@ ia: indexable: Includer messages public in le resultatos de recerca show_collections: Monstrar sequites e sequitores in le profilo unlocked: Acceptar automaticamente nove sequitores + account_alias: + acct: Pseudonymo del vetere conto + account_migration: + acct: Pseudonymo del nove conto account_warning_preset: text: Texto predefinite title: Titulo admin_account_action: + include_statuses: Includer messages reportate in le email send_email_notification: Notificar le usator per e-mail text: Advertimento personalisate type: Action @@ -118,12 +166,19 @@ ia: sensitive: Sensibile silence: Limitar suspend: Suspender + warning_preset_id: Usar un aviso predefinite announcement: + all_day: Evento quotidian + ends_at: Fin del evento + scheduled_at: Planificar publication starts_at: Initio del evento text: Annuncio + appeal: + text: Explicar perque iste decision deberea esser revertite defaults: autofollow: Invitar a sequer tu conto avatar: Pictura de profilo + bot: Isto es un conto automatisate chosen_languages: Filtrar linguas confirm_new_password: Confirmar nove contrasigno confirm_password: Confirmar contrasigno @@ -137,6 +192,7 @@ ia: header: Imagine titulo honeypot: "%{label} (non compilar)" inbox_url: URL del cassa de ingresso de repetitor + irreversible: Declinar in vice que celar locale: Lingua de interfacie max_uses: Numero max de usos new_password: Nove contrasigno @@ -145,15 +201,27 @@ ia: password: Contrasigno phrase: Parola o phrase clave setting_advanced_layout: Activar le interfacie web avantiate + setting_aggregate_reblogs: Gruppa promotiones in classificationes temporal setting_always_send_emails: Sempre inviar notificationes per e-mail + setting_auto_play_gif: Auto-reproduce GIFs animate + setting_boost_modal: Monstrar dialogo de confirmation ante promover setting_default_language: Lingua de publication + setting_default_privacy: Confidentialitate del messages + setting_default_sensitive: Sempre marcar le medios cmo sensbile + setting_delete_modal: Monstrar le dialogo de confirmation ante deler un message + setting_disable_swiping: Disactivar le movimentos per glissamento setting_display_media: Visualisation de medios setting_display_media_default: Predefinite setting_display_media_hide_all: Celar toto setting_display_media_show_all: Monstrar toto + setting_expand_spoilers: Sempre expander messages marcate con avisos de contento + setting_hide_network: Cela tu rete social + setting_reduce_motion: Reducer movimento in animationes setting_system_font_ui: Usar typo de litteras predefinite del systema setting_theme: Thema de sito setting_trends: Monstrar le tendentias de hodie + setting_unfollow_modal: Monstrar dialogo de confirmation ante cessar de sequer alcuno + setting_use_blurhash: Monstrar imagines degradate multicolor pro medios celate setting_use_pending_items: Modo lente severity: Severitate sign_in_token_attempt: Codice de securitate @@ -162,6 +230,8 @@ ia: username: Nomine de usator username_or_email: Nomine de usator o e-mail whole_word: Parola integre + email_domain_block: + with_dns_records: Includer registrationes MX e IPs del dominio featured_tag: name: Hashtag filters: @@ -169,55 +239,98 @@ ia: hide: Celar completemente warn: Celar con un advertimento form_admin_settings: + activity_api_enabled: Publicar statisticas aggregate re le activitate de usator in le API + backups_retention_period: Periodo de retention del archivo de usator bootstrap_timeline_accounts: Recommenda sempre iste contos a nove usatores + closed_registrations_message: Message personalisate quando le inscriptiones non es disponibile + content_cache_retention_period: Periodo de retention del contento remote custom_css: CSS personalisate + mascot: Personalisar le mascotte (hereditage) + media_cache_retention_period: Periodo de retention del cache multimedial + peers_api_enabled: Publicar le lista de servitores discoperite in le API profile_directory: Activar directorio de profilos + registrations_mode: Qui pote inscriber se + require_invite_text: Requirer un ration pro junger se + show_domain_blocks: Monstrar le blocadas de dominio + show_domain_blocks_rationale: Monstrar perque le dominios era blocate site_contact_email: Adresse de e-mail de contacto site_contact_username: Nomine de usator de contacto + site_extended_description: Description extense site_short_description: Description de servitor site_terms: Politica de confidentialitate site_title: Nomine de servitor status_page_url: URL del pagina de stato theme: Thema predefinite thumbnail: Miniatura de servitor + timeline_preview: Permitter accesso non authenticate a chronologias public + trendable_by_default: Permitter tendentias sin revision previe trends: Activar tendentias + trends_as_landing_page: Usar tendentias como pagina de destination + interactions: + must_be_follower: Blocar notificationes de non-sequaces + must_be_following: Blocar notificationes de gente que tu non sequer + must_be_following_dm: Blocar messages directe de gente que tu non seque invite: comment: Commento + invite_request: + text: Perque vole tu junger te? ip_block: comment: Commento ip: IP severities: no_access: Blocar le accesso + sign_up_block: Blocar inscriptiones + sign_up_requires_approval: Limitar inscriptiones severity: Regula notification_emails: + appeal: Alcuno appella un decision de moderator digest: Inviar emails compendio + favourite: Alcuno appreciava tu message + follow: Alcuno te sequeva + follow_request: Alcuno requireva de sequer te + mention: Alcuno te mentionava + pending_account: Nove conto besonia de revision + reblog: Alcuno promoveva tu message + report: Un nove reporto es inviate software_updates: all: Notificar sur tote le actualisationes critical: Notificar solmente sur actualisationes critic label: Un nove version de Mastodon es disponibile none: Nunquam notificar sur actualisationes (non recommendate) + patch: Notificar re actualisationes de correction de bug + trending_tag: Un nove tendentia require revision rule: hint: Information additional text: Regula settings: indexable: Includer pagina de profilo in le motores de recerca + show_application: Monstrar ab que app tu ha inviate un message tag: listable: Permitter a iste hashtag apparer in le recercas e suggestiones name: Hashtag + trendable: Permitter a iste hashtag de sub tendentias usable: Permitter al messages usar iste hashtag user: role: Rolo time_zone: Fuso horari user_role: + color: Color de insignia + highlighted: Monstrar le rolo como insignia sur le profilos de usator name: Nomine permissions_as_keys: Permissiones position: Prioritate webhook: events: Eventos activate + template: Modello de carga utile + url: URL de extremo 'no': 'No' not_recommended: Non recommendate + overridden: Supplantate recommended: Recommendate required: mark: "*" text: requirite + title: + sessions: + webauthn: Usa un de tu claves de securitate pro acceder 'yes': Si diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 5e35bc14c0..caf4c54299 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -77,10 +77,13 @@ ja: warn: フィルタに一致した投稿を非表示にし、フィルタのタイトルを含む警告を表示します form_admin_settings: activity_api_enabled: 週単位でローカルで公開された投稿数、アクティブユーザー数、新規登録者数を表示します + backups_retention_period: ユーザーには、後でダウンロードするために投稿のアーカイブを生成する機能があります。正の値に設定すると、これらのアーカイブは指定された日数後に自動的にストレージから削除されます。 bootstrap_timeline_accounts: これらのアカウントは、新しいユーザー向けのおすすめユーザーの一番上にピン留めされます。 closed_registrations_message: アカウント作成を停止している時に表示されます + content_cache_retention_period: 他のサーバーからのすべての投稿(ブーストや返信を含む)は、指定された日数が経過すると、ローカルユーザーとのやりとりに関係なく削除されます。これには、ローカルユーザーがブックマークやお気に入りとして登録した投稿も含まれます。異なるサーバーのユーザー間の非公開な変身も失われ、復元することは不可能です。この設定の使用は特別な目的のインスタンスのためのものであり、一般的な目的のサーバーで使用するした場合、多くのユーザーの期待を裏切ることになります。 custom_css: ウェブ版のMastodonでカスタムスタイルを適用できます。 mascot: 上級者向けWebインターフェースのイラストを上書きします。 + media_cache_retention_period: リモートユーザーが投稿したメディアファイルは、あなたのサーバーにキャッシュされます。正の値を設定すると、メディアは指定した日数後に削除されます。削除後にメディアデータが要求された場合、ソースコンテンツがまだ利用可能であれば、再ダウンロードされます。リンクプレビューカードがサードパーティのサイトを更新する頻度に制限があるため、この値を少なくとも14日に設定することをお勧めします。 peers_api_enabled: このサーバーが Fediverse で遭遇したドメイン名のリストです。このサーバーが知っているだけで、特定のサーバーと連合しているかのデータは含まれません。これは一般的に Fediverse に関する統計情報を収集するサービスによって使用されます。 profile_directory: ディレクトリには、掲載する設定をしたすべてのユーザーが一覧表示されます。 require_invite_text: アカウント登録が承認制の場合、登録の際の申請事由の入力を必須にします @@ -240,6 +243,7 @@ ja: backups_retention_period: ユーザーアーカイブの保持期間 bootstrap_timeline_accounts: おすすめユーザーに常に表示するアカウント closed_registrations_message: アカウント作成を停止している時のカスタムメッセージ + content_cache_retention_period: リモートコンテンツの保存期間 custom_css: カスタムCSS mascot: カスタムマスコット(レガシー) media_cache_retention_period: メディアキャッシュの保持期間 diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml index 3292c48289..a26468894b 100644 --- a/config/locales/simple_form.pt-PT.yml +++ b/config/locales/simple_form.pt-PT.yml @@ -77,10 +77,13 @@ pt-PT: warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro form_admin_settings: activity_api_enabled: Contagem, em blocos semanais, de publicações locais, utilizadores ativos e novos registos + backups_retention_period: Os utilizadores têm a possibilidade de gerar arquivos das suas mensagens para descarregar mais tarde. Quando definido para um valor positivo, estes arquivos serão automaticamente eliminados do seu armazenamento após o número de dias especificado. bootstrap_timeline_accounts: Estas contas serão destacadas no topo das recomendações aos novos utilizadores. closed_registrations_message: Apresentado quando as inscrições estiverem encerradas + content_cache_retention_period: Todas as publicações de outros servidores (incluindo boosts e respostas) serão eliminadas após o número de dias especificado, independentemente de qualquer interação do utilizador local com essas publicações. Isto inclui publicações em que um utilizador local as tenha marcado como favoritas ou adicionado aos items salvos. As menções privadas entre utilizadores de instâncias diferentes também se perderão e serão impossíveis de restaurar. A utilização desta definição destina-se a instâncias para fins especiais e quebra muitas expectativas dos utilizadores quando implementada para utilização geral. custom_css: Pode aplicar estilos personalizados na versão web do Mastodon. mascot: Sobrepõe-se à ilustração na interface web avançada. + media_cache_retention_period: Os ficheiros multimédia de publicações feitas por utilizadores remotos são armazenados em cache no seu servidor. Quando definido para um valor positivo, os ficheiros multimédia serão eliminados após o número de dias especificado. Se os ficheiros multimédia forem solicitados depois de terem sido eliminados, serão transferidos novamente, se o conteúdo de origem ainda estiver disponível. Devido a restrições sobre a frequência com que os cartões de pré-visualização de links pesquisam sites de terceiros, recomenda-se que este valor seja definido para, pelo menos, 14 dias, ou os cartões de pré-visualização de links não serão atualizados a pedido antes desse período. peers_api_enabled: Uma lista de nomes de domínio que este servidor encontrou no fediverso. Nenhum dado é incluído aqui sobre se você federa com um determinado servidor, apenas que o seu servidor o conhece. Este serviço é utilizado por serviços que recolhem estatísticas na federação, em termos gerais. profile_directory: O diretório de perfis lista todos os utilizadores que optaram por ter a sua conta a ser sugerida a outros. require_invite_text: Quando as incrições exigirem aprovação manual, faça o texto "Por que se quer juntar a nós?" da solicitação de convite ser obrigatório, em vez de opcional @@ -240,6 +243,7 @@ pt-PT: backups_retention_period: Período de retenção de arquivos de utilizador bootstrap_timeline_accounts: Recomendar sempre estas contas para novos utilizadores closed_registrations_message: Mensagem personalizada quando as inscrições não estiverem disponíveis + content_cache_retention_period: Período de retenção de conteúdos remotos custom_css: CSS personalizado mascot: Mascote personalizada (legado) media_cache_retention_period: Período de retenção de ficheiros de media em cache diff --git a/config/locales/simple_form.sq.yml b/config/locales/simple_form.sq.yml index a6c9303380..d545f2cd34 100644 --- a/config/locales/simple_form.sq.yml +++ b/config/locales/simple_form.sq.yml @@ -77,10 +77,13 @@ sq: warn: Fshihe lëndën e filtruar pas një sinjalizimi që përmend titullin e filtrit form_admin_settings: activity_api_enabled: Numër postimesh të botuar lokalisht, përdoruesish aktiv dhe regjistrimesh të reja sipas matjesh javore + backups_retention_period: Përdorues kanë aftësinë të prodhojnë arkiva të postimeve të tyre për t’i shkarkuar më vonë. Kur i jepet një vlerë pozitive, këto arkiva do të fshihen automatikisht prej depozitës tuaj pas numrit të dhënë të ditëve. bootstrap_timeline_accounts: Këto llogari do të fiksohen në krye të rekomandimeve për ndjekje nga përdorues të rinj. closed_registrations_message: Shfaqur kur mbyllen dritare regjistrimesh + content_cache_retention_period: Krejt postimet prej shërbyesve të tjerë (përfshi përforcime dhe përgjigje) do të fshihen pas numrit të caktuar të ditëve, pa marrë parasysh çfarëdo ndërveprimi përdoruesi me këto postime. Kjo përfshin postime kur një përdorues vendor u ka vënë shenjë si faqerojtës, ose të parapëlqyer. Do të humbin gjithashtu dhe përmendje private mes përdoruesish nga instanca të ndryshme dhe s’do të jetë e mundshme të rikthehen. Përdorimi i këtij rregullimi është menduar për instanca me qëllim të caktuar dhe ndërhyn në çka presin mjaft përdorues, kur sendërtohet për përdorim të përgjithshëm. custom_css: Stile vetjakë mund të aplikoni në versionin web të Mastodon-it. mascot: Anashkalon ilustrimin te ndërfaqja web e thelluar. + media_cache_retention_period: Kartela media nga postime të bëra nga përdorues të largët ruhen në një fshehtinë në shërbyesin tuaj. Kur i jepet një vlerë pozitive, media do të fshihet pas numrit të dhënë të ditëve. Nëse të dhënat e medias duhen pas fshirjes, do të rishkarkohen, nëse lënda burim mund të kihet ende. Për shkak kufizimesh mbi sa shpesh skeda paraparjesh lidhjesh ndërveprojnë me sajte palësh të treta, rekomandohet të vihet kjo vlerë të paktën 14 ditë, ose skedat e paraparjes së lidhje s’do të përditësohen duke e kërkuar para asaj kohe. peers_api_enabled: Një listë emrash përkatësish që ky shërbyes ka hasur në fedivers. Këtu s’jepen të dhëna nëse jeni i federuar me shërbyesin e dhënë, thjesht tregohet se shërbyesi juaj e njeh. Kjo përdoret nga shërbime që mbledhin statistika mbi federimin në kuptimin e përgjithshëm. profile_directory: Drejtoria e profileve paraqet krejt përdoruesit që kanë zgjedhur të jenë të zbulueshëm. require_invite_text: Kur regjistrimet lypin miratim dorazi, bëje tekstin “Përse doni të bëheni pjesë?” të detyrueshëm, në vend se opsional @@ -240,6 +243,7 @@ sq: backups_retention_period: Periudhë mbajtjeje arkivash përdoruesish bootstrap_timeline_accounts: Rekomandoju përherë këto llogari përdoruesve të rinj closed_registrations_message: Mesazh vetjak për pamundësi regjistrimesh të reja + content_cache_retention_period: Periudhë mbajtjeje lënde të largët custom_css: CSS Vetjake mascot: Simbol vetjak (e dikurshme) media_cache_retention_period: Periudhë mbajtjeje lënde media diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml index bfc2d2e6b6..e68642c2f6 100644 --- a/config/locales/simple_form.th.yml +++ b/config/locales/simple_form.th.yml @@ -77,8 +77,10 @@ th: warn: ซ่อนเนื้อหาที่กรองอยู่หลังคำเตือนที่กล่าวถึงชื่อเรื่องของตัวกรอง form_admin_settings: activity_api_enabled: จำนวนโพสต์ที่เผยแพร่ในเซิร์ฟเวอร์, ผู้ใช้ที่ใช้งานอยู่ และการลงทะเบียนใหม่ในบักเก็ตรายสัปดาห์ + backups_retention_period: ผู้ใช้มีความสามารถในการสร้างการเก็บถาวรของโพสต์ของเขาเพื่อดาวน์โหลดในภายหลัง เมื่อตั้งเป็นค่าบวก จะลบการเก็บถาวรเหล่านี้ออกจากที่เก็บข้อมูลของคุณโดยอัตโนมัติหลังจากจำนวนวันที่ระบุ bootstrap_timeline_accounts: จะปักหมุดบัญชีเหล่านี้ไว้ด้านบนสุดของคำแนะนำการติดตามของผู้ใช้ใหม่ closed_registrations_message: แสดงเมื่อมีการปิดการลงทะเบียน + content_cache_retention_period: จะลบโพสต์ทั้งหมดจากเซิร์ฟเวอร์อื่น ๆ (รวมถึงการดันและการตอบกลับ) หลังจากจำนวนวันที่ระบุ โดยไม่คำนึงถึงการโต้ตอบใด ๆ ของผู้ใช้ในเซิร์ฟเวอร์กับโพสต์เหล่านั้น สิ่งนี้รวมถึงโพสต์ที่ผู้ใช้ในเซิร์ฟเวอร์ได้ทำเครื่องหมายโพสต์ว่าเป็นที่คั่นหน้าหรือรายการโปรด การกล่าวถึงแบบส่วนตัวระหว่างผู้ใช้จากอินสแตนซ์ที่แตกต่างกันจะหายไปและไม่สามารถคืนค่าได้เช่นกัน การใช้การตั้งค่านี้มีไว้สำหรับอินสแตนซ์ที่มีวัตถุประสงค์พิเศษและทำลายความคาดหวังของผู้ใช้จำนวนมากเมื่อนำไปใช้สำหรับการใช้งานที่มีวัตถุประสงค์ทั่วไป custom_css: คุณสามารถนำไปใช้ลักษณะที่กำหนดเองใน Mastodon รุ่นเว็บ mascot: เขียนทับภาพประกอบในส่วนติดต่อเว็บขั้นสูง peers_api_enabled: รายการชื่อโดเมนที่เซิร์ฟเวอร์นี้พบในจักรวาลสหพันธ์ ไม่มีข้อมูลรวมอยู่ที่นี่เกี่ยวกับว่าคุณติดต่อกับเซิร์ฟเวอร์ที่กำหนดหรือไม่ เพียงแค่ว่าเซิร์ฟเวอร์ของคุณทราบเกี่ยวกับเซิร์ฟเวอร์ที่กำหนด มีการใช้สิ่งนี้โดยบริการที่เก็บรวบรวมสถิติในการติดต่อกับภายนอกในความหมายทั่วไป diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 400059770b..78e7bdb25e 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -524,6 +524,7 @@ sk: many: "%{count} poznámok" one: "%{count} poznámka" other: "%{count} poznámky" + action_log: Denník auditu action_taken_by: Zákrok vykonal/a actions: suspend_description_html: Tento účet a všetok jeho obsah bude nedostupný a nakoniec zmazaný, interaktovať s ním bude nemožné. Zvrátiteľné v rámci 30 dní. Uzatvára všetky hlásenia voči tomuto účtu. diff --git a/config/locales/sl.yml b/config/locales/sl.yml index ff23e64841..6c26511ad6 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -779,6 +779,7 @@ sl: desc_html: To se zanaša na zunanje skripte hCaptcha in lahko predstavlja tveganje za varnost in zasebnost. Poleg tega to lahko nekaterim ljudem (posebno invalidom) občutno oteži dostopnost registracijskega postopka. Zato svetujemo, da razmislite o drugih ukrepih, kot je na primer registracija na podlagi odobritve ali povabila. title: Od novih uporabnikov zahtevaj reševanje CAPTCHA za potrditev računov content_retention: + danger_zone: Območje nevarnosti preamble: Nazdor nad hrambo vsebine uporabnikov v Mastodonu. title: Hramba vsebin default_noindex: diff --git a/config/locales/sq.yml b/config/locales/sq.yml index dcacb46bf9..8319cfcaec 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -748,6 +748,7 @@ sq: desc_html: Kjo bazohet në programthe të jashtëm prej hCaptcha, çka mund të përbëjë një shqetësim për sigurinë dhe privatësinë. Veç kësaj, kjo mund ta bëjë procesin e regjistrimit në shkallë të madhe më pak të përdorshëm për disa persona (veçanërisht ata me paaftësi). Për këto arsye, ju lutemi, shihni mundësinë e masave alternative, fjala vjen, bazuar në miratim, ose regjistrim vetëm me ftesa. title: Kërko prej përdoruesve të rinj të zgjidhin një CAPTCHA, si ripohim të llogarisë të tyre content_retention: + danger_zone: Zonë rreziku preamble: Kontrolloni se si depozitohen në Mastodon lënda e prodhuar nga përdoruesit. title: Mbajtje lënde default_noindex: diff --git a/config/locales/th.yml b/config/locales/th.yml index 0d7483d79a..8a001d8755 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -1837,6 +1837,7 @@ th: explanation: นี่คือเคล็ดลับบางส่วนที่จะช่วยให้คุณเริ่มต้นใช้งาน feature_action: เรียนรู้เพิ่มเติม feature_audience: Mastodon มีความพิเศษที่ให้คุณจัดการผู้รับสารของคุณได้โดยไม่มีตัวกลาง นอกจากนี้ การติดตั้ง Mastodon บนโครงสร้างพื้นฐานของคุณจะทำให้คุณสามารถติดตาม (และติดตามโดย) เซิร์ฟเวอร์ Mastodon แห่งไหนก็ได้ที่ทำงานอยู่ โดยไม่มีใครสามารถควบคุมได้นอกจากคุณ + feature_audience_title: สร้างผู้ชมของคุณด้วยความมั่นใจ follow_action: ติดตาม follow_step: การติดตามผู้คนที่น่าสนใจคือสิ่งที่ Mastodon ให้ความสำคัญ follow_title: ปรับแต่งฟีดหน้าแรกของคุณ From 86f17e4b32eb5da3dfcd82c4be72d529d8a72565 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 10:46:17 +0200 Subject: [PATCH 092/658] Update devDependencies (non-major) (#30185) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 53 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index ddc789b5fe..26ffbcee1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2212,16 +2212,37 @@ __metadata: linkType: hard "@formatjs/cli@npm:^6.1.1": - version: 6.2.9 - resolution: "@formatjs/cli@npm:6.2.9" + version: 6.2.10 + resolution: "@formatjs/cli@npm:6.2.10" peerDependencies: + "@glimmer/env": ^0.1.7 + "@glimmer/reference": ^0.91.1 + "@glimmer/syntax": ^0.91.1 + "@glimmer/validator": ^0.91.1 + "@vue/compiler-core": ^3.4.0 + content-tag: ^2.0.1 + ember-template-recast: ^6.1.4 vue: ^3.4.0 peerDependenciesMeta: + "@glimmer/env": + optional: true + "@glimmer/reference": + optional: true + "@glimmer/syntax": + optional: true + "@glimmer/validator": + optional: true + "@vue/compiler-core": + optional: true + content-tag: + optional: true + ember-template-recast: + optional: true vue: optional: true bin: formatjs: bin/formatjs - checksum: 10c0/498383bcdca7f8f8a748c1151be17392f71eb1861f6a23bc714280533167cba7cdc35a470a380113f6111236e721ff43cbee7b084939dac67b6a5d9b04c0587c + checksum: 10c0/34b1b0b3be25d945111c1f57913f50da7308ecd05501a27eaca210a774eb50c616b5706ba796d37ffa223ac4c5cddd5f36fe0ca8d31ad8c8ade79cdd497ccfb9 languageName: node linkType: hard @@ -3334,8 +3355,8 @@ __metadata: linkType: hard "@testing-library/jest-dom@npm:^6.0.0": - version: 6.4.2 - resolution: "@testing-library/jest-dom@npm:6.4.2" + version: 6.4.5 + resolution: "@testing-library/jest-dom@npm:6.4.5" dependencies: "@adobe/css-tools": "npm:^4.3.2" "@babel/runtime": "npm:^7.9.2" @@ -3343,7 +3364,7 @@ __metadata: chalk: "npm:^3.0.0" css.escape: "npm:^1.5.1" dom-accessibility-api: "npm:^0.6.3" - lodash: "npm:^4.17.15" + lodash: "npm:^4.17.21" redent: "npm:^3.0.0" peerDependencies: "@jest/globals": ">= 28" @@ -3362,21 +3383,25 @@ __metadata: optional: true vitest: optional: true - checksum: 10c0/e7eba527b34ce30cde94424d2ec685bdfed51daaafb7df9b68b51aec6052e99a50c8bfe654612dacdf857a1eb81d68cf294fc89de558ee3a992bf7a6019fffcc + checksum: 10c0/4cfdd44e2abab2b9d399c47cbfe686729bb65160d7df0f9e2329aaaea7702f6e852a9eefb29b468f00c1e5a5274b684f8cac76959d33299dfa909ba007ea191d languageName: node linkType: hard "@testing-library/react@npm:^15.0.0": - version: 15.0.5 - resolution: "@testing-library/react@npm:15.0.5" + version: 15.0.6 + resolution: "@testing-library/react@npm:15.0.6" dependencies: "@babel/runtime": "npm:^7.12.5" "@testing-library/dom": "npm:^10.0.0" "@types/react-dom": "npm:^18.0.0" peerDependencies: + "@types/react": ^18.0.0 react: ^18.0.0 react-dom: ^18.0.0 - checksum: 10c0/8759cc8e7e6b4d8964f151d8872ea3c91b6ef6d8fb3b9116fae53350b9a6b29e5ad45b18408c22525924d050263f7ea77cd17ca803918759f22a760f68a42227 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/3705a2272f929f2f848f5d7e6ac9829bf7ecc1725a35733ffae7e7a261d4bdab470b080558e8544edb1f9ba25db9fbc4232527df9b4ec6ab6ae4462a902a7f95 languageName: node linkType: hard @@ -11403,7 +11428,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21": +"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.20, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c @@ -16438,8 +16463,8 @@ __metadata: linkType: hard "stylelint@npm:^16.0.2": - version: 16.4.0 - resolution: "stylelint@npm:16.4.0" + version: 16.5.0 + resolution: "stylelint@npm:16.5.0" dependencies: "@csstools/css-parser-algorithms": "npm:^2.6.1" "@csstools/css-tokenizer": "npm:^2.2.4" @@ -16482,7 +16507,7 @@ __metadata: write-file-atomic: "npm:^5.0.1" bin: stylelint: bin/stylelint.mjs - checksum: 10c0/7e603a0d88732180b60528c9f2edfca7fdf8c966f42c260af16131854c3acb5acfa30403b1f4fd72cd1470eb9ba625ca4de84e8cb379942df54127c55afc1288 + checksum: 10c0/9281693ff6c1918e07fdcf7a950531f79678a28261a0d5bd36ca2fcf524e53d7305158d20ba890f5dd01c0ff90c09a13453dce2fe6887f4c157d8c2c0acf3666 languageName: node linkType: hard From 00c34070ae3679116f4962b5608b53fa95a61e1b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 10:46:22 +0200 Subject: [PATCH 093/658] Update eslint (non-major) (#30186) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 102 +++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/yarn.lock b/yarn.lock index 26ffbcee1f..785df92e51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4107,14 +4107,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^7.0.0": - version: 7.7.1 - resolution: "@typescript-eslint/eslint-plugin@npm:7.7.1" + version: 7.8.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.8.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.7.1" - "@typescript-eslint/type-utils": "npm:7.7.1" - "@typescript-eslint/utils": "npm:7.7.1" - "@typescript-eslint/visitor-keys": "npm:7.7.1" + "@typescript-eslint/scope-manager": "npm:7.8.0" + "@typescript-eslint/type-utils": "npm:7.8.0" + "@typescript-eslint/utils": "npm:7.8.0" + "@typescript-eslint/visitor-keys": "npm:7.8.0" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" @@ -4127,25 +4127,25 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/11a085240e7daf4bdeb011aa53ac7cfeea6263c60d53607823f5c314eb5c9d559b28fce0d6686acb9702ee3d0cb0406534fafae61163e5a903eaf818c48194ad + checksum: 10c0/37ca22620d1834ff0baa28fa4b8fd92039a3903cb95748353de32d56bae2a81ce50d1bbaed27487eebc884e0a0f9387fcb0f1647593e4e6df5111ef674afa9f0 languageName: node linkType: hard "@typescript-eslint/parser@npm:^7.0.0": - version: 7.7.1 - resolution: "@typescript-eslint/parser@npm:7.7.1" + version: 7.8.0 + resolution: "@typescript-eslint/parser@npm:7.8.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.7.1" - "@typescript-eslint/types": "npm:7.7.1" - "@typescript-eslint/typescript-estree": "npm:7.7.1" - "@typescript-eslint/visitor-keys": "npm:7.7.1" + "@typescript-eslint/scope-manager": "npm:7.8.0" + "@typescript-eslint/types": "npm:7.8.0" + "@typescript-eslint/typescript-estree": "npm:7.8.0" + "@typescript-eslint/visitor-keys": "npm:7.8.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/ace43eeb8123bbee61e936650e1d57a2cf70f2030870c6dcad8602fce3f7cdf2cce350121dbbc66cffd60bac36652f426a1c5293c45ed28998b90cd95673b5c9 + checksum: 10c0/0dd994c1b31b810c25e1b755b8d352debb7bf21a31f9a91acaec34acf4e471320bcceaa67cf64c110c0b8f5fac10a037dbabac6ec423e17adf037e59a7bce9c1 languageName: node linkType: hard @@ -4159,22 +4159,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.7.1": - version: 7.7.1 - resolution: "@typescript-eslint/scope-manager@npm:7.7.1" +"@typescript-eslint/scope-manager@npm:7.8.0": + version: 7.8.0 + resolution: "@typescript-eslint/scope-manager@npm:7.8.0" dependencies: - "@typescript-eslint/types": "npm:7.7.1" - "@typescript-eslint/visitor-keys": "npm:7.7.1" - checksum: 10c0/4032da8fce8922044a6b659c8435ba203377778d5b7de6a5572c1172f2e3cf8ddd890a0f9e083c5d5315a9c2dba323707528ee4ad3cc1be2bd334de2527ef5cb + "@typescript-eslint/types": "npm:7.8.0" + "@typescript-eslint/visitor-keys": "npm:7.8.0" + checksum: 10c0/c253b98e96d4bf0375f473ca2c4d081726f1fd926cdfa65ee14c9ee99cca8eddb763b2d238ac365daa7246bef21b0af38180d04e56e9df7443c0e6f8474d097c languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.7.1": - version: 7.7.1 - resolution: "@typescript-eslint/type-utils@npm:7.7.1" +"@typescript-eslint/type-utils@npm:7.8.0": + version: 7.8.0 + resolution: "@typescript-eslint/type-utils@npm:7.8.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.7.1" - "@typescript-eslint/utils": "npm:7.7.1" + "@typescript-eslint/typescript-estree": "npm:7.8.0" + "@typescript-eslint/utils": "npm:7.8.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependencies: @@ -4182,7 +4182,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/bd083c4106e207aa8c2a71251eca52d23c7ea905399b8c62004f3bb1e85b9c88d601db9dcecae88beef0f8362d53450bb2721aab353ee731c1665496fea3fbda + checksum: 10c0/00f6315626b64f7dbc1f7fba6f365321bb8d34141ed77545b2a07970e59a81dbdf768c1e024225ea00953750d74409ddd8a16782fc4a39261e507c04192dacab languageName: node linkType: hard @@ -4193,10 +4193,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.7.1": - version: 7.7.1 - resolution: "@typescript-eslint/types@npm:7.7.1" - checksum: 10c0/7d240503d9d0b12d68c8204167690609f02ededb77dcb035c1c8b932da08cf43553829c29a5f7889824a7337463c300343bc5abe532479726d4c83443a7e2704 +"@typescript-eslint/types@npm:7.8.0": + version: 7.8.0 + resolution: "@typescript-eslint/types@npm:7.8.0" + checksum: 10c0/b2fdbfc21957bfa46f7d8809b607ad8c8b67c51821d899064d09392edc12f28b2318a044f0cd5d523d782e84e8f0558778877944964cf38e139f88790cf9d466 languageName: node linkType: hard @@ -4219,12 +4219,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.7.1": - version: 7.7.1 - resolution: "@typescript-eslint/typescript-estree@npm:7.7.1" +"@typescript-eslint/typescript-estree@npm:7.8.0": + version: 7.8.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.8.0" dependencies: - "@typescript-eslint/types": "npm:7.7.1" - "@typescript-eslint/visitor-keys": "npm:7.7.1" + "@typescript-eslint/types": "npm:7.8.0" + "@typescript-eslint/visitor-keys": "npm:7.8.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -4234,24 +4234,24 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/c6b32bd96fd13b9da0a30de01935066f7505f6214f5759e3cd019f7d1852f7bf19358765f62e51de72be47647656aa0e8f07ac0ab316c4149a4e6bd1dd12cbb6 + checksum: 10c0/1690b62679685073dcb0f62499f0b52b445b37ae6e12d02aa4acbafe3fb023cf999b01f714b6282e88f84fd934fe3e2eefb21a64455d19c348d22bbc68ca8e47 languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.7.1": - version: 7.7.1 - resolution: "@typescript-eslint/utils@npm:7.7.1" +"@typescript-eslint/utils@npm:7.8.0": + version: 7.8.0 + resolution: "@typescript-eslint/utils@npm:7.8.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.15" "@types/semver": "npm:^7.5.8" - "@typescript-eslint/scope-manager": "npm:7.7.1" - "@typescript-eslint/types": "npm:7.7.1" - "@typescript-eslint/typescript-estree": "npm:7.7.1" + "@typescript-eslint/scope-manager": "npm:7.8.0" + "@typescript-eslint/types": "npm:7.8.0" + "@typescript-eslint/typescript-estree": "npm:7.8.0" semver: "npm:^7.6.0" peerDependencies: eslint: ^8.56.0 - checksum: 10c0/0986b8c297d6bfdbd2ac8cd3bcf447ef9b934e2dae536771d3368a5c284a0b16c0ea041f82aa100c48d05acc33198e1a3d9d721d3319ae80abba0f5e69c21633 + checksum: 10c0/31fb58388d15b082eb7bd5bce889cc11617aa1131dfc6950471541b3df64c82d1c052e2cccc230ca4ae80456d4f63a3e5dccb79899a8f3211ce36c089b7d7640 languageName: node linkType: hard @@ -4282,13 +4282,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.7.1": - version: 7.7.1 - resolution: "@typescript-eslint/visitor-keys@npm:7.7.1" +"@typescript-eslint/visitor-keys@npm:7.8.0": + version: 7.8.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.8.0" dependencies: - "@typescript-eslint/types": "npm:7.7.1" + "@typescript-eslint/types": "npm:7.8.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/19cbd14ac9a234d847f457cbd880cbd98b83c331a46d2dc2d8c0e6cb54ce6159552f6dd2f7236035be1a71f13f48df4a2aa09e70ad1f1e2ff3da7c3622927bd3 + checksum: 10c0/5892fb5d9c58efaf89adb225f7dbbb77f9363961f2ff420b6b130bdd102dddd7aa8a16c46a5a71c19889d27b781e966119a89270555ea2cb5653a04d8994123d languageName: node linkType: hard @@ -7772,8 +7772,8 @@ __metadata: linkType: hard "eslint-plugin-formatjs@npm:^4.10.1": - version: 4.13.0 - resolution: "eslint-plugin-formatjs@npm:4.13.0" + version: 4.13.1 + resolution: "eslint-plugin-formatjs@npm:4.13.1" dependencies: "@formatjs/icu-messageformat-parser": "npm:2.7.6" "@formatjs/ts-transformer": "npm:3.13.12" @@ -7788,7 +7788,7 @@ __metadata: unicode-emoji-utils: "npm:^1.2.0" peerDependencies: eslint: 7 || 8 - checksum: 10c0/3dbe4ffd3e72d4ce5b14afdcf6dd5db889dd09cb15bc875f29bcc5b49295e0ae4a3eb672ed89ed33f22aacbfe655151398ca4307fd0610508e568a6e4db50aa8 + checksum: 10c0/ce18141dff84e8fe026127085c1a63279acb3a1bc0b70dc1ddce2fc65bb37d68ccf6d097231428745eda2caea42080e1c80a01a1895803155c15123a01bfeee3 languageName: node linkType: hard From 4f0d18168c39a52250b8be07558675716bf292ee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 10:46:43 +0200 Subject: [PATCH 094/658] Update DefinitelyTyped types (non-major) (#30184) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/yarn.lock b/yarn.lock index 785df92e51..acaab739aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3702,9 +3702,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.195": - version: 4.17.0 - resolution: "@types/lodash@npm:4.17.0" - checksum: 10c0/4c5b41c9a6c41e2c05d08499e96f7940bcf194dcfa84356235b630da920c2a5e05f193618cea76006719bec61c76617dff02defa9d29934f9f6a76a49291bd8f + version: 4.17.1 + resolution: "@types/lodash@npm:4.17.1" + checksum: 10c0/af2ad8a3c8d7deb170a7ec6e18afc5ae8980576e5f7fe798d8a95a1df7222c15bdf967a25a35879f575a3b64743de00145710ee461a0051e055e94e4fe253f45 languageName: node linkType: hard @@ -3760,13 +3760,13 @@ __metadata: linkType: hard "@types/pg@npm:^8.6.6": - version: 8.11.5 - resolution: "@types/pg@npm:8.11.5" + version: 8.11.6 + resolution: "@types/pg@npm:8.11.6" dependencies: "@types/node": "npm:*" pg-protocol: "npm:*" pg-types: "npm:^4.0.1" - checksum: 10c0/d64d183bee2df96cd0558231190ff629558e8c0fd3203b880f48a7d34b1eaea528d20c09b57b19c0939f369136e6c6941533592eadd71174be78d1ec0ca5e60e + checksum: 10c0/e68e057d9500b25cd776f4fcc547b4880c4f3b0c7b6e03c8a0e5e262b6189dd7a00f4edc8937ffc55a9f6a136a78d7e4a9b6bbe6a46122a95c134f7be66f6842 languageName: node linkType: hard @@ -3820,11 +3820,11 @@ __metadata: linkType: hard "@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.4": - version: 18.2.25 - resolution: "@types/react-dom@npm:18.2.25" + version: 18.3.0 + resolution: "@types/react-dom@npm:18.3.0" dependencies: "@types/react": "npm:*" - checksum: 10c0/87604407eca6884c5b4d4657cb511dc5ba28ea1cfa5d0ce1fc2d659a7ad1b64ae85dcda60e3f010641f9a52a6a60dfcaa6be3b0d0de9d624475052a13dae01f4 + checksum: 10c0/6c90d2ed72c5a0e440d2c75d99287e4b5df3e7b011838cdc03ae5cd518ab52164d86990e73246b9d812eaf02ec351d74e3b4f5bd325bf341e13bf980392fd53b languageName: node linkType: hard @@ -3896,11 +3896,11 @@ __metadata: linkType: hard "@types/react-test-renderer@npm:^18.0.0": - version: 18.0.7 - resolution: "@types/react-test-renderer@npm:18.0.7" + version: 18.3.0 + resolution: "@types/react-test-renderer@npm:18.3.0" dependencies: "@types/react": "npm:*" - checksum: 10c0/45cbe963354acee2ab090979d856763c84f59ef7b63477d1fef5d0fd52760b69aa67bbd205fbd3bd36264620fce72c8e407735a9f2009c40ca50da59b0058c34 + checksum: 10c0/3c9748be52e8e659e7adf91dea6939486463264e6f633bf21c4cb116de18af7bef0595568a1e588160420b2f65289473075dda1cb417c2875df8cf7a09f5d913 languageName: node linkType: hard @@ -3923,12 +3923,12 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7": - version: 18.2.79 - resolution: "@types/react@npm:18.2.79" + version: 18.3.1 + resolution: "@types/react@npm:18.3.1" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10c0/c8a8a005d8830a48cc1ef93c3510c4935a2a03e5557dbecaa8f1038450cbfcb18eb206fa7fba7077d54b8da21faeb25577e897a333392770a7797f625b62c78a + checksum: 10c0/18d856c12a4ec93f3cda2d58ef3d77a9480818afd3af895f812896fb82cfca1f35a692ab1add4ce826a4eb58a071624c7d1c8c6c4ccfb81c100d2916dc607614 languageName: node linkType: hard From e5062b713588cbdc7249a65311a2e59a08bf9731 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 6 May 2024 11:52:34 +0200 Subject: [PATCH 095/658] Fix post deletion not being deferred when those are part of an account warning (#30163) --- app/models/status.rb | 2 +- spec/models/status_spec.rb | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/app/models/status.rb b/app/models/status.rb index 0bb5c0ce23..72a8d6c40e 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -266,7 +266,7 @@ class Status < ApplicationRecord end def reported? - @reported ||= Report.where(target_account: account).unresolved.exists?(['? = ANY(status_ids)', id]) + @reported ||= account.targeted_reports.unresolved.exists?(['? = ANY(status_ids)', id]) || account.strikes.exists?(['? = ANY(status_ids)', id.to_s]) end def emojis diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 284576ceda..271cf8690e 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -205,6 +205,48 @@ RSpec.describe Status do end end + describe '#reported?' do + context 'when the status is not reported' do + it 'returns false' do + expect(subject.reported?).to be false + end + end + + context 'when the status is part of an open report' do + before do + Fabricate(:report, target_account: subject.account, status_ids: [subject.id]) + end + + it 'returns true' do + expect(subject.reported?).to be true + end + end + + context 'when the status is part of a closed report with an account warning mentioning the account' do + before do + report = Fabricate(:report, target_account: subject.account, status_ids: [subject.id]) + report.resolve!(Fabricate(:account)) + Fabricate(:account_warning, target_account: subject.account, status_ids: [subject.id], report: report) + end + + it 'returns true' do + expect(subject.reported?).to be true + end + end + + context 'when the status is part of a closed report with an account warning not mentioning the account' do + before do + report = Fabricate(:report, target_account: subject.account, status_ids: [subject.id]) + report.resolve!(Fabricate(:account)) + Fabricate(:account_warning, target_account: subject.account, report: report) + end + + it 'returns false' do + expect(subject.reported?).to be false + end + end + end + describe '.mutes_map' do subject { described_class.mutes_map([status.conversation.id], account) } From dbaa4ed891f5eb97e74600ddd4e38a9be40f9180 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 6 May 2024 07:50:45 -0400 Subject: [PATCH 096/658] Use `chewy` which relaxes ES version reqs (#30157) --- Gemfile.lock | 16 ++++++++-------- .../system_check/elasticsearch_check_spec.rb | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 27d858ed05..190888ddb8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -167,9 +167,9 @@ GEM activesupport cbor (0.5.9.8) charlock_holmes (0.7.7) - chewy (7.5.1) + chewy (7.6.0) activesupport (>= 5.2) - elasticsearch (>= 7.12.0, < 7.14.0) + elasticsearch (>= 7.14.0, < 8) elasticsearch-dsl chunky_png (1.4.0) climate_control (1.2.0) @@ -220,14 +220,14 @@ GEM dotenv (3.1.1) drb (2.2.1) ed25519 (1.3.0) - elasticsearch (7.13.3) - elasticsearch-api (= 7.13.3) - elasticsearch-transport (= 7.13.3) - elasticsearch-api (7.13.3) + elasticsearch (7.17.10) + elasticsearch-api (= 7.17.10) + elasticsearch-transport (= 7.17.10) + elasticsearch-api (7.17.10) multi_json elasticsearch-dsl (0.1.10) - elasticsearch-transport (7.13.3) - faraday (~> 1) + elasticsearch-transport (7.17.10) + faraday (>= 1, < 3) multi_json email_spec (2.2.2) htmlentities (~> 4.3.3) diff --git a/spec/lib/admin/system_check/elasticsearch_check_spec.rb b/spec/lib/admin/system_check/elasticsearch_check_spec.rb index a885640ce0..8f210579d0 100644 --- a/spec/lib/admin/system_check/elasticsearch_check_spec.rb +++ b/spec/lib/admin/system_check/elasticsearch_check_spec.rb @@ -127,7 +127,7 @@ describe Admin::SystemCheck::ElasticsearchCheck do end def stub_elasticsearch_error - client = instance_double(Elasticsearch::Transport::Client) + client = instance_double(Elasticsearch::Client) allow(client).to receive(:info).and_raise(Elasticsearch::Transport::Transport::Error) allow(Chewy).to receive(:client).and_return(client) end From 8e4fea77e311399e4bcfff729aa06fed4e82e57c Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 6 May 2024 14:41:14 +0200 Subject: [PATCH 097/658] Fix race condition in `POST /api/v1/push/subscription` (#30166) --- .../api/v1/push/subscriptions_controller.rb | 33 ++++++++++++------- app/lib/access_token_extension.rb | 2 ++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/v1/push/subscriptions_controller.rb b/app/controllers/api/v1/push/subscriptions_controller.rb index 3634acf956..e1ad89ee3e 100644 --- a/app/controllers/api/v1/push/subscriptions_controller.rb +++ b/app/controllers/api/v1/push/subscriptions_controller.rb @@ -1,9 +1,12 @@ # frozen_string_literal: true class Api::V1::Push::SubscriptionsController < Api::BaseController + include Redisable + include Lockable + before_action -> { doorkeeper_authorize! :push } before_action :require_user! - before_action :set_push_subscription + before_action :set_push_subscription, only: [:show, :update] before_action :check_push_subscription, only: [:show, :update] def show @@ -11,16 +14,18 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController end def create - @push_subscription&.destroy! + with_redis_lock("push_subscription:#{current_user.id}") do + destroy_web_push_subscriptions! - @push_subscription = Web::PushSubscription.create!( - endpoint: subscription_params[:endpoint], - key_p256dh: subscription_params[:keys][:p256dh], - key_auth: subscription_params[:keys][:auth], - data: data_params, - user_id: current_user.id, - access_token_id: doorkeeper_token.id - ) + @push_subscription = Web::PushSubscription.create!( + endpoint: subscription_params[:endpoint], + key_p256dh: subscription_params[:keys][:p256dh], + key_auth: subscription_params[:keys][:auth], + data: data_params, + user_id: current_user.id, + access_token_id: doorkeeper_token.id + ) + end render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer end @@ -31,14 +36,18 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController end def destroy - @push_subscription&.destroy! + destroy_web_push_subscriptions! render_empty end private + def destroy_web_push_subscriptions! + doorkeeper_token.web_push_subscriptions.destroy_all + end + def set_push_subscription - @push_subscription = Web::PushSubscription.find_by(access_token_id: doorkeeper_token.id) + @push_subscription = doorkeeper_token.web_push_subscriptions.first end def check_push_subscription diff --git a/app/lib/access_token_extension.rb b/app/lib/access_token_extension.rb index f51bde4927..4e9585dd1e 100644 --- a/app/lib/access_token_extension.rb +++ b/app/lib/access_token_extension.rb @@ -6,6 +6,8 @@ module AccessTokenExtension included do include Redisable + has_many :web_push_subscriptions, class_name: 'Web::PushSubscription', inverse_of: :access_token + after_commit :push_to_streaming_api end From 30ef9fccf0c603ba917191ddbefdd497523d3d67 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 6 May 2024 14:47:19 +0200 Subject: [PATCH 098/658] Fix hashtag matching pattern matching some link anchors (#30190) --- app/models/tag.rb | 2 +- spec/models/tag_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/tag.rb b/app/models/tag.rb index 35be921e2d..3f88cb0680 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -37,7 +37,7 @@ class Tag < ApplicationRecord HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)' HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}" - HASHTAG_RE = %r{(? Date: Mon, 6 May 2024 15:17:56 +0200 Subject: [PATCH 099/658] Implement RFC 8414 for OAuth 2.0 server metadata (#29191) --- .../well_known/oauth_metadata_controller.rb | 23 +++++++ app/presenters/oauth_metadata_presenter.rb | 67 +++++++++++++++++++ app/serializers/oauth_metadata_serializer.rb | 9 +++ config/routes.rb | 1 + .../well_known/oauth_metadata_spec.rb | 37 ++++++++++ 5 files changed, 137 insertions(+) create mode 100644 app/controllers/well_known/oauth_metadata_controller.rb create mode 100644 app/presenters/oauth_metadata_presenter.rb create mode 100644 app/serializers/oauth_metadata_serializer.rb create mode 100644 spec/requests/well_known/oauth_metadata_spec.rb diff --git a/app/controllers/well_known/oauth_metadata_controller.rb b/app/controllers/well_known/oauth_metadata_controller.rb new file mode 100644 index 0000000000..c80be2d652 --- /dev/null +++ b/app/controllers/well_known/oauth_metadata_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module WellKnown + class OauthMetadataController < ActionController::Base # rubocop:disable Rails/ApplicationController + include CacheConcern + + # Prevent `active_model_serializer`'s `ActionController::Serialization` from calling `current_user` + # and thus re-issuing session cookies + serialization_scope nil + + def show + # Due to this document potentially changing between Mastodon versions (as + # new OAuth scopes are added), we don't use expires_in to cache upstream, + # instead just caching in the rails cache: + render_with_cache( + json: ::OauthMetadataPresenter.new, + serializer: ::OauthMetadataSerializer, + content_type: 'application/json', + expires_in: 15.minutes + ) + end + end +end diff --git a/app/presenters/oauth_metadata_presenter.rb b/app/presenters/oauth_metadata_presenter.rb new file mode 100644 index 0000000000..546503bfcc --- /dev/null +++ b/app/presenters/oauth_metadata_presenter.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +class OauthMetadataPresenter < ActiveModelSerializers::Model + include RoutingHelper + + attributes :issuer, :authorization_endpoint, :token_endpoint, + :revocation_endpoint, :scopes_supported, + :response_types_supported, :response_modes_supported, + :grant_types_supported, :token_endpoint_auth_methods_supported, + :service_documentation, :app_registration_endpoint + + def issuer + root_url + end + + def service_documentation + 'https://docs.joinmastodon.org/' + end + + def authorization_endpoint + oauth_authorization_url + end + + def token_endpoint + oauth_token_url + end + + # As the api_v1_apps route doesn't technically conform to the specification + # for OAuth 2.0 Dynamic Client Registration defined in RFC 7591 we use a + # non-standard property for now to indicate the mastodon specific registration + # endpoint. See: https://datatracker.ietf.org/doc/html/rfc7591 + def app_registration_endpoint + api_v1_apps_url + end + + def revocation_endpoint + oauth_revoke_url + end + + def scopes_supported + doorkeeper.scopes + end + + def response_types_supported + doorkeeper.authorization_response_types + end + + def response_modes_supported + doorkeeper.authorization_response_flows.flat_map(&:response_mode_matches).uniq + end + + def grant_types_supported + grant_types_supported = doorkeeper.grant_flows.dup + grant_types_supported << 'refresh_token' if doorkeeper.refresh_token_enabled? + grant_types_supported + end + + def token_endpoint_auth_methods_supported + %w(client_secret_basic client_secret_post) + end + + private + + def doorkeeper + @doorkeeper ||= Doorkeeper.configuration + end +end diff --git a/app/serializers/oauth_metadata_serializer.rb b/app/serializers/oauth_metadata_serializer.rb new file mode 100644 index 0000000000..5f3dc7b87e --- /dev/null +++ b/app/serializers/oauth_metadata_serializer.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class OauthMetadataSerializer < ActiveModel::Serializer + attributes :issuer, :authorization_endpoint, :token_endpoint, + :revocation_endpoint, :scopes_supported, + :response_types_supported, :response_modes_supported, + :grant_types_supported, :token_endpoint_auth_methods_supported, + :service_documentation, :app_registration_endpoint +end diff --git a/config/routes.rb b/config/routes.rb index 3d3c94096c..f4662dd5da 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -62,6 +62,7 @@ Rails.application.routes.draw do tokens: 'oauth/tokens' end + get '.well-known/oauth-authorization-server', to: 'well_known/oauth_metadata#show', as: :oauth_metadata, defaults: { format: 'json' } get '.well-known/host-meta', to: 'well_known/host_meta#show', as: :host_meta, defaults: { format: 'xml' } get '.well-known/nodeinfo', to: 'well_known/node_info#index', as: :nodeinfo, defaults: { format: 'json' } get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger diff --git a/spec/requests/well_known/oauth_metadata_spec.rb b/spec/requests/well_known/oauth_metadata_spec.rb new file mode 100644 index 0000000000..deef189ac9 --- /dev/null +++ b/spec/requests/well_known/oauth_metadata_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'The /.well-known/oauth-authorization-server request' do + let(:protocol) { ENV.fetch('LOCAL_HTTPS', true) ? :https : :http } + + before do + host! ENV.fetch('LOCAL_DOMAIN') + end + + it 'returns http success with valid JSON response' do + get '/.well-known/oauth-authorization-server' + + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: 'application/json' + ) + + grant_types_supported = Doorkeeper.configuration.grant_flows.dup + grant_types_supported << 'refresh_token' if Doorkeeper.configuration.refresh_token_enabled? + + expect(body_as_json).to include( + issuer: root_url(protocol: protocol), + service_documentation: 'https://docs.joinmastodon.org/', + authorization_endpoint: oauth_authorization_url(protocol: protocol), + token_endpoint: oauth_token_url(protocol: protocol), + revocation_endpoint: oauth_revoke_url(protocol: protocol), + scopes_supported: Doorkeeper.configuration.scopes.map(&:to_s), + response_types_supported: Doorkeeper.configuration.authorization_response_types, + grant_types_supported: grant_types_supported, + # non-standard extension: + app_registration_endpoint: api_v1_apps_url(protocol: protocol) + ) + end +end From 05126d106fd972e4baf5a1cec857e44a451b90a9 Mon Sep 17 00:00:00 2001 From: Fawaz Farid Date: Mon, 6 May 2024 16:31:39 +0300 Subject: [PATCH 100/658] Redirect back after site upload deletion (#30141) --- app/controllers/admin/site_uploads_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/site_uploads_controller.rb b/app/controllers/admin/site_uploads_controller.rb index a5d2cf41cf..96e61cf6bb 100644 --- a/app/controllers/admin/site_uploads_controller.rb +++ b/app/controllers/admin/site_uploads_controller.rb @@ -9,7 +9,7 @@ module Admin @site_upload.destroy! - redirect_to admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg') + redirect_back fallback_location: admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg') end private From b152f936c1361cc82e21c853335557c3ffa80409 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 6 May 2024 11:05:12 -0400 Subject: [PATCH 101/658] Migrate paperclip `_file_size` columns to bigint (#29263) Co-authored-by: Claire --- .../instance_media_attachments_measure.rb | 2 +- ...51_convert_file_size_columns_to_big_int.rb | 42 +++++++++++++++++++ db/schema.rb | 16 +++---- 3 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 db/migrate/20240217175251_convert_file_size_columns_to_big_int.rb diff --git a/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb b/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb index 1d2dbbe414..65f444624e 100644 --- a/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb +++ b/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb @@ -50,7 +50,7 @@ class Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure < Admin::Metrics: WHERE date_trunc('day', media_attachments.created_at)::date = axis.period AND #{account_domain_sql(params[:include_subdomains])} ) - SELECT COALESCE(SUM(size), 0) FROM new_media_attachments + SELECT COALESCE(SUM(size), 0)::bigint FROM new_media_attachments ) AS value FROM ( SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period diff --git a/db/migrate/20240217175251_convert_file_size_columns_to_big_int.rb b/db/migrate/20240217175251_convert_file_size_columns_to_big_int.rb new file mode 100644 index 0000000000..f8223f9c93 --- /dev/null +++ b/db/migrate/20240217175251_convert_file_size_columns_to_big_int.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require_relative '../../lib/mastodon/migration_helpers' + +class ConvertFileSizeColumnsToBigInt < ActiveRecord::Migration[7.1] + include Mastodon::MigrationHelpers + + TABLE_COLUMN_MAPPING = [ + [:accounts, :avatar_file_size], + [:accounts, :header_file_size], + [:custom_emojis, :image_file_size], + [:imports, :data_file_size], + [:media_attachments, :file_file_size], + [:media_attachments, :thumbnail_file_size], + [:preview_cards, :image_file_size], + [:site_uploads, :file_file_size], + ].freeze + + disable_ddl_transaction! + + def migrate_columns(to_type) + TABLE_COLUMN_MAPPING.each do |column_parts| + table, column = column_parts + + # Skip this if we're resuming and already did this one. + next if column_for(table, column).sql_type == to_type.to_s + + safety_assured do + change_column_type_concurrently table, column, to_type + cleanup_concurrent_column_type_change table, column + end + end + end + + def up + migrate_columns(:bigint) + end + + def down + migrate_columns(:integer) + end +end diff --git a/db/schema.rb b/db/schema.rb index 11f1a202f7..ee41a0c3a1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -166,11 +166,11 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.string "url" t.string "avatar_file_name" t.string "avatar_content_type" - t.integer "avatar_file_size" + t.bigint "avatar_file_size" t.datetime "avatar_updated_at", precision: nil t.string "header_file_name" t.string "header_content_type" - t.integer "header_file_size" + t.bigint "header_file_size" t.datetime "header_updated_at", precision: nil t.string "avatar_remote_url" t.boolean "locked", default: false, null: false @@ -368,7 +368,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.string "domain" t.string "image_file_name" t.string "image_content_type" - t.integer "image_file_size" + t.bigint "image_file_size" t.datetime "image_updated_at", precision: nil t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false @@ -558,7 +558,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.datetime "updated_at", precision: nil, null: false t.string "data_file_name" t.string "data_content_type" - t.integer "data_file_size" + t.bigint "data_file_size" t.datetime "data_updated_at", precision: nil t.bigint "account_id", null: false t.boolean "overwrite", default: false, null: false @@ -635,7 +635,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.bigint "status_id" t.string "file_file_name" t.string "file_content_type" - t.integer "file_file_size" + t.bigint "file_file_size" t.datetime "file_updated_at", precision: nil t.string "remote_url", default: "", null: false t.datetime "created_at", precision: nil, null: false @@ -651,7 +651,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.integer "file_storage_schema_version" t.string "thumbnail_file_name" t.string "thumbnail_content_type" - t.integer "thumbnail_file_size" + t.bigint "thumbnail_file_size" t.datetime "thumbnail_updated_at", precision: nil t.string "thumbnail_remote_url" t.index ["account_id", "status_id"], name: "index_media_attachments_on_account_id_and_status_id", order: { status_id: :desc } @@ -855,7 +855,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.string "description", default: "", null: false t.string "image_file_name" t.string "image_content_type" - t.integer "image_file_size" + t.bigint "image_file_size" t.datetime "image_updated_at", precision: nil t.integer "type", default: 0, null: false t.text "html", default: "", null: false @@ -993,7 +993,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.string "var", default: "", null: false t.string "file_file_name" t.string "file_content_type" - t.integer "file_file_size" + t.bigint "file_file_size" t.datetime "file_updated_at", precision: nil t.json "meta" t.datetime "created_at", precision: nil, null: false From bc24c4792d0bef744ff1d39e8eb543b1b6aa98c2 Mon Sep 17 00:00:00 2001 From: Fawaz Farid Date: Mon, 6 May 2024 18:06:52 +0300 Subject: [PATCH 102/658] Allow admins to configure instance favicon and logo (#30040) --- app/helpers/application_helper.rb | 7 +++++ app/models/form/admin_settings.rb | 4 +++ app/models/site_upload.rb | 8 ++++++ app/serializers/manifest_serializer.rb | 20 ++++--------- .../admin/settings/branding/show.html.haml | 28 +++++++++++++++++++ app/views/layouts/application.html.haml | 10 +++---- config/locales/simple_form.en-GB.yml | 3 ++ config/locales/simple_form.en.yml | 2 ++ spec/helpers/application_helper_spec.rb | 24 ++++++++++++++++ 9 files changed, 87 insertions(+), 19 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 4cf959f2d8..ff351429e0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -240,6 +240,13 @@ module ApplicationHelper EmojiFormatter.new(html, custom_emojis, other_options.merge(animate: prefers_autoplay?)).to_s end + def site_icon_path(type, size = '48') + icon = SiteUpload.find_by(var: type) + return nil unless icon + + icon.file.url(size) + end + private def storage_host_var diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index cb37a52217..85b913cf80 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -37,6 +37,8 @@ class Form::AdminSettings status_page_url captcha_enabled authorized_fetch + app_icon + favicon ).freeze INTEGER_KEYS = %i( @@ -63,6 +65,8 @@ class Form::AdminSettings UPLOAD_KEYS = %i( thumbnail mascot + app_icon + favicon ).freeze OVERRIDEN_SETTINGS = { diff --git a/app/models/site_upload.rb b/app/models/site_upload.rb index 03d472cdb2..b3926ec7ed 100644 --- a/app/models/site_upload.rb +++ b/app/models/site_upload.rb @@ -19,7 +19,15 @@ class SiteUpload < ApplicationRecord include Attachmentable + FAVICON_SIZES = [16, 32, 48].freeze + APPLE_ICON_SIZES = [57, 60, 72, 76, 114, 120, 144, 152, 167, 180, 1024].freeze + ANDROID_ICON_SIZES = [36, 48, 72, 96, 144, 192, 256, 384, 512].freeze + + APP_ICON_SIZES = (APPLE_ICON_SIZES + ANDROID_ICON_SIZES).uniq.freeze + STYLES = { + app_icon: APP_ICON_SIZES.each_with_object({}) { |size, hash| hash[size.to_s.to_sym] = "#{size}x#{size}#" }.freeze, + favicon: FAVICON_SIZES.each_with_object({}) { |size, hash| hash[size.to_s.to_sym] = "#{size}x#{size}#" }.freeze, thumbnail: { '@1x': { format: 'png', diff --git a/app/serializers/manifest_serializer.rb b/app/serializers/manifest_serializer.rb index 1c1f7d0ad5..759490228c 100644 --- a/app/serializers/manifest_serializer.rb +++ b/app/serializers/manifest_serializer.rb @@ -1,21 +1,10 @@ # frozen_string_literal: true class ManifestSerializer < ActiveModel::Serializer + include ApplicationHelper include RoutingHelper include ActionView::Helpers::TextHelper - ICON_SIZES = %w( - 36 - 48 - 72 - 96 - 144 - 192 - 256 - 384 - 512 - ).freeze - attributes :id, :name, :short_name, :icons, :theme_color, :background_color, :display, :start_url, :scope, @@ -37,9 +26,12 @@ class ManifestSerializer < ActiveModel::Serializer end def icons - ICON_SIZES.map do |size| + SiteUpload::ANDROID_ICON_SIZES.map do |size| + src = site_icon_path('app_icon', size.to_i) + src = URI.join(root_url, src).to_s if src.present? + { - src: frontend_asset_url("icons/android-chrome-#{size}x#{size}.png"), + src: src || frontend_asset_url("icons/android-chrome-#{size}x#{size}.png"), sizes: "#{size}x#{size}", type: 'image/png', purpose: 'any maskable', diff --git a/app/views/admin/settings/branding/show.html.haml b/app/views/admin/settings/branding/show.html.haml index 769c0dafe8..71aac5ead1 100644 --- a/app/views/admin/settings/branding/show.html.haml +++ b/app/views/admin/settings/branding/show.html.haml @@ -40,5 +40,33 @@ = fa_icon 'trash fw' = t('admin.site_uploads.delete') + .fields-row + .fields-row__column.fields-row__column-6.fields-group + = f.input :favicon, + as: :file, + input_html: { accept: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].join(',') }, + wrapper: :with_block_label + + .fields-row__column.fields-row__column-6.fields-group + - if @admin_settings.favicon.persisted? + = image_tag @admin_settings.favicon.file.url('48'), class: 'fields-group__thumbnail' + = link_to admin_site_upload_path(@admin_settings.favicon), data: { method: :delete }, class: 'link-button link-button--destructive' do + = fa_icon 'trash fw' + = t('admin.site_uploads.delete') + + .fields-row + .fields-row__column.fields-row__column-6.fields-group + = f.input :app_icon, + as: :file, + input_html: { accept: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].join(',') }, + wrapper: :with_block_label + + .fields-row__column.fields-row__column-6.fields-group + - if @admin_settings.app_icon.persisted? + = image_tag @admin_settings.app_icon.file.url('48'), class: 'fields-group__thumbnail' + = link_to admin_site_upload_path(@admin_settings.app_icon), data: { method: :delete }, class: 'link-button link-button--destructive' do + = fa_icon 'trash fw' + = t('admin.site_uploads.delete') + .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 9d7669d685..56857b2b63 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -11,13 +11,13 @@ - if storage_host? %link{ rel: 'dns-prefetch', href: storage_host }/ - %link{ rel: 'icon', href: '/favicon.ico', type: 'image/x-icon' }/ + %link{ rel: 'icon', href: site_icon_path('favicon') || '/favicon.ico', type: 'image/x-icon' }/ - - %w(16 32 48).each do |size| - %link{ rel: 'icon', sizes: "#{size}x#{size}", href: frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/ + - SiteUpload::FAVICON_SIZES.each do |size| + %link{ rel: 'icon', sizes: "#{size}x#{size}", href: site_icon_path('favicon', size.to_i) || frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/ - - %w(57 60 72 76 114 120 144 152 167 180 1024).each do |size| - %link{ rel: 'apple-touch-icon', sizes: "#{size}x#{size}", href: frontend_asset_path("icons/apple-touch-icon-#{size}x#{size}.png") }/ + - SiteUpload::APPLE_ICON_SIZES.each do |size| + %link{ rel: 'apple-touch-icon', sizes: "#{size}x#{size}", href: site_icon_path('app_icon', size.to_i) || frontend_asset_path("icons/apple-touch-icon-#{size}x#{size}.png") }/ %link{ rel: 'mask-icon', href: frontend_asset_path('images/logo-symbol-icon.svg'), color: '#6364FF' }/ %link{ rel: 'manifest', href: manifest_path(format: :json) }/ diff --git a/config/locales/simple_form.en-GB.yml b/config/locales/simple_form.en-GB.yml index f4668ccada..9aedac15f3 100644 --- a/config/locales/simple_form.en-GB.yml +++ b/config/locales/simple_form.en-GB.yml @@ -77,9 +77,12 @@ en-GB: warn: Hide the filtered content behind a warning mentioning the filter's title form_admin_settings: activity_api_enabled: Counts of locally published posts, active users, and new registrations in weekly buckets + app_icon: WEBP, PNG, GIF or JPG. Overrides the default app icon on mobile devices with a custom icon. + backups_retention_period: Keep generated user archives for the specified number of days. bootstrap_timeline_accounts: These accounts will be pinned to the top of new users' follow recommendations. closed_registrations_message: Displayed when sign-ups are closed custom_css: You can apply custom styles on the web version of Mastodon. + favicon: WEBP, PNG, GIF or JPG. Overrides the default Mastodon favicon with a custom icon. mascot: Overrides the illustration in the advanced web interface. peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense. profile_directory: The profile directory lists all users who have opted-in to be discoverable. diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 7304bdc22f..fdc9f61813 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -77,11 +77,13 @@ en: warn: Hide the filtered content behind a warning mentioning the filter's title form_admin_settings: activity_api_enabled: Counts of locally published posts, active users, and new registrations in weekly buckets + app_icon: WEBP, PNG, GIF or JPG. Overrides the default app icon on mobile devices with a custom icon. backups_retention_period: Users have the ability to generate archives of their posts to download later. When set to a positive value, these archives will be automatically deleted from your storage after the specified number of days. bootstrap_timeline_accounts: These accounts will be pinned to the top of new users' follow recommendations. closed_registrations_message: Displayed when sign-ups are closed content_cache_retention_period: All posts from other servers (including boosts and replies) will be deleted after the specified number of days, without regard to any local user interaction with those posts. This includes posts where a local user has marked it as bookmarks or favorites. Private mentions between users from different instances will also be lost and impossible to restore. Use of this setting is intended for special purpose instances and breaks many user expectations when implemented for general purpose use. custom_css: You can apply custom styles on the web version of Mastodon. + favicon: WEBP, PNG, GIF or JPG. Overrides the default Mastodon favicon with a custom icon. mascot: Overrides the illustration in the advanced web interface. media_cache_retention_period: Media files from posts made by remote users are cached on your server. When set to a positive value, media will be deleted after the specified number of days. If the media data is requested after it is deleted, it will be re-downloaded, if the source content is still available. Due to restrictions on how often link preview cards poll third-party sites, it is recommended to set this value to at least 14 days, or link preview cards will not be updated on demand before that time. peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense. diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 9330eb0dae..56501034b2 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -285,4 +285,28 @@ describe ApplicationHelper do end end end + + describe '#site_icon_path' do + context 'when an icon exists' do + let!(:favicon) { Fabricate(:site_upload, var: 'favicon') } + + it 'returns the URL of the icon' do + expect(helper.site_icon_path('favicon')).to eq(favicon.file.url('48')) + end + + it 'returns the URL of the icon with size parameter' do + expect(helper.site_icon_path('favicon', 16)).to eq(favicon.file.url('16')) + end + end + + context 'when an icon does not exist' do + it 'returns nil' do + expect(helper.site_icon_path('favicon')).to be_nil + end + + it 'returns nil with size parameter' do + expect(helper.site_icon_path('favicon', 16)).to be_nil + end + end + end end From 2fe1b8d1695d8faa452a69872fde94ccc4611576 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 6 May 2024 17:19:15 +0200 Subject: [PATCH 103/658] Add API to get multiple accounts and statuses (#27871) Co-authored-by: noellabo --- app/controllers/api/v1/accounts_controller.rb | 30 ++++++++++++++++--- app/controllers/api/v1/statuses_controller.rb | 29 ++++++++++++++++-- .../concerns/status/threading_concern.rb | 27 +++++++++++------ config/routes/api.rb | 4 +-- spec/requests/api/v1/accounts_spec.rb | 16 ++++++++++ spec/requests/api/v1/statuses_spec.rb | 16 ++++++++++ 6 files changed, 104 insertions(+), 18 deletions(-) diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index 23fc85b475..be7b302d3b 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -9,16 +9,22 @@ class Api::V1::AccountsController < Api::BaseController before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, only: [:block, :unblock] before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create] - before_action :require_user!, except: [:show, :create] - before_action :set_account, except: [:create] - before_action :check_account_approval, except: [:create] - before_action :check_account_confirmation, except: [:create] + before_action :require_user!, except: [:index, :show, :create] + before_action :set_account, except: [:index, :create] + before_action :set_accounts, only: [:index] + before_action :check_account_approval, except: [:index, :create] + before_action :check_account_confirmation, except: [:index, :create] before_action :check_enabled_registrations, only: [:create] + before_action :check_accounts_limit, only: [:index] skip_before_action :require_authenticated_user!, only: :create override_rate_limit_headers :follow, family: :follows + def index + render json: @accounts, each_serializer: REST::AccountSerializer + end + def show cache_if_unauthenticated! render json: @account, serializer: REST::AccountSerializer @@ -79,6 +85,10 @@ class Api::V1::AccountsController < Api::BaseController @account = Account.find(params[:id]) end + def set_accounts + @accounts = Account.where(id: account_ids).without_unapproved + end + def check_account_approval raise(ActiveRecord::RecordNotFound) if @account.local? && @account.user_pending? end @@ -87,10 +97,22 @@ class Api::V1::AccountsController < Api::BaseController raise(ActiveRecord::RecordNotFound) if @account.local? && !@account.user_confirmed? end + def check_accounts_limit + raise(Mastodon::ValidationError) if account_ids.size > DEFAULT_ACCOUNTS_LIMIT + end + def relationships(**options) AccountRelationshipsPresenter.new([@account], current_user.account_id, **options) end + def account_ids + Array(accounts_params[:ids]).uniq.map(&:to_i) + end + + def accounts_params + params.permit(ids: []) + end + def account_params params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone, :invite_code) end diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 01c3718763..36a9ec6325 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -5,9 +5,11 @@ class Api::V1::StatusesController < Api::BaseController before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :update, :destroy] before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :update, :destroy] - before_action :require_user!, except: [:show, :context] - before_action :set_status, only: [:show, :context] - before_action :set_thread, only: [:create] + before_action :require_user!, except: [:index, :show, :context] + before_action :set_statuses, only: [:index] + before_action :set_status, only: [:show, :context] + before_action :set_thread, only: [:create] + before_action :check_statuses_limit, only: [:index] override_rate_limit_headers :create, family: :statuses override_rate_limit_headers :update, family: :statuses @@ -23,6 +25,11 @@ class Api::V1::StatusesController < Api::BaseController DESCENDANTS_LIMIT = 60 DESCENDANTS_DEPTH_LIMIT = 20 + def index + @statuses = cache_collection(@statuses, Status) + render json: @statuses, each_serializer: REST::StatusSerializer + end + def show cache_if_unauthenticated! @status = cache_collection([@status], Status).first @@ -111,6 +118,10 @@ class Api::V1::StatusesController < Api::BaseController private + def set_statuses + @statuses = Status.permitted_statuses_from_ids(status_ids, current_account) + end + def set_status @status = Status.find(params[:id]) authorize @status, :show? @@ -125,6 +136,18 @@ class Api::V1::StatusesController < Api::BaseController render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404 end + def check_statuses_limit + raise(Mastodon::ValidationError) if status_ids.size > DEFAULT_STATUSES_LIMIT + end + + def status_ids + Array(statuses_params[:ids]).uniq.map(&:to_i) + end + + def statuses_params + params.permit(ids: []) + end + def status_params params.permit( :status, diff --git a/app/models/concerns/status/threading_concern.rb b/app/models/concerns/status/threading_concern.rb index ca8c448140..478a139d63 100644 --- a/app/models/concerns/status/threading_concern.rb +++ b/app/models/concerns/status/threading_concern.rb @@ -3,6 +3,23 @@ module Status::ThreadingConcern extend ActiveSupport::Concern + class_methods do + def permitted_statuses_from_ids(ids, account, stable: false) + statuses = Status.with_accounts(ids).to_a + account_ids = statuses.map(&:account_id).uniq + domains = statuses.filter_map(&:account_domain).uniq + relations = account&.relations_map(account_ids, domains) || {} + + statuses.reject! { |status| StatusFilter.new(status, account, relations).filtered? } + + if stable + statuses.sort_by! { |status| ids.index(status.id) } + else + statuses + end + end + end + def ancestors(limit, account = nil) find_statuses_from_tree_path(ancestor_ids(limit), account) end @@ -76,15 +93,7 @@ module Status::ThreadingConcern end def find_statuses_from_tree_path(ids, account, promote: false) - statuses = Status.with_accounts(ids).to_a - account_ids = statuses.map(&:account_id).uniq - domains = statuses.filter_map(&:account_domain).uniq - relations = account&.relations_map(account_ids, domains) || {} - - statuses.reject! { |status| StatusFilter.new(status, account, relations).filtered? } - - # Order ancestors/descendants by tree path - statuses.sort_by! { |status| ids.index(status.id) } + statuses = Status.permitted_statuses_from_ids(ids, account, stable: true) # Bring self-replies to the top if promote diff --git a/config/routes/api.rb b/config/routes/api.rb index 60fb0394e7..bf3cee0c10 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -6,7 +6,7 @@ namespace :api, format: false do # JSON / REST API namespace :v1 do - resources :statuses, only: [:create, :show, :update, :destroy] do + resources :statuses, only: [:index, :create, :show, :update, :destroy] do scope module: :statuses do resources :reblogged_by, controller: :reblogged_by_accounts, only: :index resources :favourited_by, controller: :favourited_by_accounts, only: :index @@ -182,7 +182,7 @@ namespace :api, format: false do resources :familiar_followers, only: :index end - resources :accounts, only: [:create, :show] do + resources :accounts, only: [:index, :create, :show] do scope module: :accounts do resources :statuses, only: :index resources :followers, only: :index, controller: :follower_accounts diff --git a/spec/requests/api/v1/accounts_spec.rb b/spec/requests/api/v1/accounts_spec.rb index e543c41360..55f8e1c6fa 100644 --- a/spec/requests/api/v1/accounts_spec.rb +++ b/spec/requests/api/v1/accounts_spec.rb @@ -8,6 +8,22 @@ describe '/api/v1/accounts' do let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + describe 'GET /api/v1/accounts?ids[]=:id' do + let(:account) { Fabricate(:account) } + let(:other_account) { Fabricate(:account) } + let(:scopes) { 'read:accounts' } + + it 'returns expected response' do + get '/api/v1/accounts', headers: headers, params: { ids: [account.id, other_account.id, 123_123] } + + expect(response).to have_http_status(200) + expect(body_as_json).to contain_exactly( + hash_including(id: account.id.to_s), + hash_including(id: other_account.id.to_s) + ) + end + end + describe 'GET /api/v1/accounts/:id' do context 'when logged out' do let(:account) { Fabricate(:account) } diff --git a/spec/requests/api/v1/statuses_spec.rb b/spec/requests/api/v1/statuses_spec.rb index a3b84afa26..0b2d1f90cf 100644 --- a/spec/requests/api/v1/statuses_spec.rb +++ b/spec/requests/api/v1/statuses_spec.rb @@ -9,6 +9,22 @@ describe '/api/v1/statuses' do let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: client_app, scopes: scopes) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + describe 'GET /api/v1/statuses?ids[]=:id' do + let(:status) { Fabricate(:status) } + let(:other_status) { Fabricate(:status) } + let(:scopes) { 'read:statuses' } + + it 'returns expected response' do + get '/api/v1/statuses', headers: headers, params: { ids: [status.id, other_status.id, 123_123] } + + expect(response).to have_http_status(200) + expect(body_as_json).to contain_exactly( + hash_including(id: status.id.to_s), + hash_including(id: other_status.id.to_s) + ) + end + end + describe 'GET /api/v1/statuses/:id' do subject do get "/api/v1/statuses/#{status.id}", headers: headers From 616789454707be00b334070646491b5e028d3be6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 19:14:46 +0200 Subject: [PATCH 104/658] Update dependency pino-http to v10 (#30191) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- streaming/package.json | 2 +- yarn.lock | 42 ++++++++++++++---------------------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/streaming/package.json b/streaming/package.json index c4dcccf1f5..f08d2a4c2d 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -25,7 +25,7 @@ "pg": "^8.5.0", "pg-connection-string": "^2.6.0", "pino": "^9.0.0", - "pino-http": "^9.0.0", + "pino-http": "^10.0.0", "prom-client": "^15.0.0", "uuid": "^9.0.0", "ws": "^8.12.1" diff --git a/yarn.lock b/yarn.lock index acaab739aa..399dae2057 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2927,7 +2927,7 @@ __metadata: pg: "npm:^8.5.0" pg-connection-string: "npm:^2.6.0" pino: "npm:^9.0.0" - pino-http: "npm:^9.0.0" + pino-http: "npm:^10.0.0" pino-pretty: "npm:^11.0.0" prom-client: "npm:^15.0.0" typescript: "npm:^5.0.4" @@ -12993,7 +12993,7 @@ __metadata: languageName: node linkType: hard -"pino-abstract-transport@npm:^1.0.0, pino-abstract-transport@npm:^1.1.0, pino-abstract-transport@npm:^1.2.0": +"pino-abstract-transport@npm:^1.0.0, pino-abstract-transport@npm:^1.2.0": version: 1.2.0 resolution: "pino-abstract-transport@npm:1.2.0" dependencies: @@ -13003,15 +13003,15 @@ __metadata: languageName: node linkType: hard -"pino-http@npm:^9.0.0": - version: 9.0.0 - resolution: "pino-http@npm:9.0.0" +"pino-http@npm:^10.0.0": + version: 10.0.0 + resolution: "pino-http@npm:10.0.0" dependencies: get-caller-file: "npm:^2.0.5" - pino: "npm:^8.17.1" - pino-std-serializers: "npm:^6.2.2" + pino: "npm:^9.0.0" + pino-std-serializers: "npm:^7.0.0" process-warning: "npm:^3.0.0" - checksum: 10c0/05496cb76cc9908658e50c4620fbdf7b0b5d99fb529493d601c3e4635b0bf7ce12b8a8eed7b5b520089f643b099233d61dd71f7cdfad8b66e59b9b81d79b6512 + checksum: 10c0/40d2dcb2bc0c51f1ce45d3d7144c54f087fe1a122d82d0f497d65656151a1603a64f82f62d7fc6a3c172754c5a5cf6105b3096620eece31cefbc8cf95b26c062 languageName: node linkType: hard @@ -13039,31 +13039,17 @@ __metadata: languageName: node linkType: hard -"pino-std-serializers@npm:^6.0.0, pino-std-serializers@npm:^6.2.2": +"pino-std-serializers@npm:^6.0.0": version: 6.2.2 resolution: "pino-std-serializers@npm:6.2.2" checksum: 10c0/8f1c7f0f0d8f91e6c6b5b2a6bfb48f06441abeb85f1c2288319f736f9c6d814fbeebe928d2314efc2ba6018fa7db9357a105eca9fc99fc1f28945a8a8b28d3d5 languageName: node linkType: hard -"pino@npm:^8.17.1": - version: 8.20.0 - resolution: "pino@npm:8.20.0" - dependencies: - atomic-sleep: "npm:^1.0.0" - fast-redact: "npm:^3.1.1" - on-exit-leak-free: "npm:^2.1.0" - pino-abstract-transport: "npm:^1.1.0" - pino-std-serializers: "npm:^6.0.0" - process-warning: "npm:^3.0.0" - quick-format-unescaped: "npm:^4.0.3" - real-require: "npm:^0.2.0" - safe-stable-stringify: "npm:^2.3.1" - sonic-boom: "npm:^3.7.0" - thread-stream: "npm:^2.0.0" - bin: - pino: bin.js - checksum: 10c0/6b973474160e1fa01fa150de0f69b7db9c6c06ae15f992d369669751825c8f2af3bb5600348eaf9be65b4952326bbdfa226f51e425820eb511f0f594fbddbaa7 +"pino-std-serializers@npm:^7.0.0": + version: 7.0.0 + resolution: "pino-std-serializers@npm:7.0.0" + checksum: 10c0/73e694d542e8de94445a03a98396cf383306de41fd75ecc07085d57ed7a57896198508a0dec6eefad8d701044af21eb27253ccc352586a03cf0d4a0bd25b4133 languageName: node linkType: hard @@ -16787,7 +16773,7 @@ __metadata: languageName: node linkType: hard -"thread-stream@npm:^2.0.0, thread-stream@npm:^2.6.0": +"thread-stream@npm:^2.6.0": version: 2.6.0 resolution: "thread-stream@npm:2.6.0" dependencies: From 996292cd55e661f3390792b60b130150b1f4ff40 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 7 May 2024 10:41:53 +0200 Subject: [PATCH 105/658] Fix `db:encryption:init` requiring ActiveRecord encryption variables to be set (#30202) --- lib/tasks/db.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 07de087766..d6377c9c82 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -6,7 +6,7 @@ Rake::Task['db:encryption:init'].clear namespace :db do namespace :encryption do desc 'Generate a set of keys for configuring Active Record encryption in a given environment' - task init: :environment do + task :init do # rubocop:disable Rails/RakeEnvironment puts <<~MSG Add these environment variables to your Mastodon environment:#{' '} From 96fb6e491ffa526e800b5c3d1835022a90930c88 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 7 May 2024 10:46:05 +0200 Subject: [PATCH 106/658] Revert "Migrate paperclip `_file_size` columns to bigint (#29263)" (#30203) --- .../instance_media_attachments_measure.rb | 2 +- ...51_convert_file_size_columns_to_big_int.rb | 42 ------------------- db/schema.rb | 16 +++---- 3 files changed, 9 insertions(+), 51 deletions(-) delete mode 100644 db/migrate/20240217175251_convert_file_size_columns_to_big_int.rb diff --git a/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb b/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb index 65f444624e..1d2dbbe414 100644 --- a/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb +++ b/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb @@ -50,7 +50,7 @@ class Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure < Admin::Metrics: WHERE date_trunc('day', media_attachments.created_at)::date = axis.period AND #{account_domain_sql(params[:include_subdomains])} ) - SELECT COALESCE(SUM(size), 0)::bigint FROM new_media_attachments + SELECT COALESCE(SUM(size), 0) FROM new_media_attachments ) AS value FROM ( SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period diff --git a/db/migrate/20240217175251_convert_file_size_columns_to_big_int.rb b/db/migrate/20240217175251_convert_file_size_columns_to_big_int.rb deleted file mode 100644 index f8223f9c93..0000000000 --- a/db/migrate/20240217175251_convert_file_size_columns_to_big_int.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../lib/mastodon/migration_helpers' - -class ConvertFileSizeColumnsToBigInt < ActiveRecord::Migration[7.1] - include Mastodon::MigrationHelpers - - TABLE_COLUMN_MAPPING = [ - [:accounts, :avatar_file_size], - [:accounts, :header_file_size], - [:custom_emojis, :image_file_size], - [:imports, :data_file_size], - [:media_attachments, :file_file_size], - [:media_attachments, :thumbnail_file_size], - [:preview_cards, :image_file_size], - [:site_uploads, :file_file_size], - ].freeze - - disable_ddl_transaction! - - def migrate_columns(to_type) - TABLE_COLUMN_MAPPING.each do |column_parts| - table, column = column_parts - - # Skip this if we're resuming and already did this one. - next if column_for(table, column).sql_type == to_type.to_s - - safety_assured do - change_column_type_concurrently table, column, to_type - cleanup_concurrent_column_type_change table, column - end - end - end - - def up - migrate_columns(:bigint) - end - - def down - migrate_columns(:integer) - end -end diff --git a/db/schema.rb b/db/schema.rb index ee41a0c3a1..11f1a202f7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -166,11 +166,11 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.string "url" t.string "avatar_file_name" t.string "avatar_content_type" - t.bigint "avatar_file_size" + t.integer "avatar_file_size" t.datetime "avatar_updated_at", precision: nil t.string "header_file_name" t.string "header_content_type" - t.bigint "header_file_size" + t.integer "header_file_size" t.datetime "header_updated_at", precision: nil t.string "avatar_remote_url" t.boolean "locked", default: false, null: false @@ -368,7 +368,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.string "domain" t.string "image_file_name" t.string "image_content_type" - t.bigint "image_file_size" + t.integer "image_file_size" t.datetime "image_updated_at", precision: nil t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false @@ -558,7 +558,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.datetime "updated_at", precision: nil, null: false t.string "data_file_name" t.string "data_content_type" - t.bigint "data_file_size" + t.integer "data_file_size" t.datetime "data_updated_at", precision: nil t.bigint "account_id", null: false t.boolean "overwrite", default: false, null: false @@ -635,7 +635,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.bigint "status_id" t.string "file_file_name" t.string "file_content_type" - t.bigint "file_file_size" + t.integer "file_file_size" t.datetime "file_updated_at", precision: nil t.string "remote_url", default: "", null: false t.datetime "created_at", precision: nil, null: false @@ -651,7 +651,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.integer "file_storage_schema_version" t.string "thumbnail_file_name" t.string "thumbnail_content_type" - t.bigint "thumbnail_file_size" + t.integer "thumbnail_file_size" t.datetime "thumbnail_updated_at", precision: nil t.string "thumbnail_remote_url" t.index ["account_id", "status_id"], name: "index_media_attachments_on_account_id_and_status_id", order: { status_id: :desc } @@ -855,7 +855,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.string "description", default: "", null: false t.string "image_file_name" t.string "image_content_type" - t.bigint "image_file_size" + t.integer "image_file_size" t.datetime "image_updated_at", precision: nil t.integer "type", default: 0, null: false t.text "html", default: "", null: false @@ -993,7 +993,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.string "var", default: "", null: false t.string "file_file_name" t.string "file_content_type" - t.bigint "file_file_size" + t.integer "file_file_size" t.datetime "file_updated_at", precision: nil t.json "meta" t.datetime "created_at", precision: nil, null: false From ed556db3953d7585cc78a92597f1e3dca9cc2b53 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 11:36:16 +0200 Subject: [PATCH 107/658] New Crowdin Translations (automated) (#30201) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ca.json | 3 +- app/javascript/mastodon/locales/fi.json | 4 +- app/javascript/mastodon/locales/lt.json | 3 +- app/javascript/mastodon/locales/uk.json | 31 +++++ config/locales/devise.ia.yml | 2 + config/locales/doorkeeper.lt.yml | 8 +- config/locales/ia.yml | 171 ++++++++++++++++++++++++ config/locales/lt.yml | 78 ++++++++--- config/locales/simple_form.ca.yml | 2 + config/locales/simple_form.da.yml | 2 + config/locales/simple_form.de.yml | 2 + config/locales/simple_form.en-GB.yml | 3 - config/locales/simple_form.es-AR.yml | 2 + config/locales/simple_form.eu.yml | 2 + config/locales/simple_form.fi.yml | 2 + config/locales/simple_form.fo.yml | 2 + config/locales/simple_form.gl.yml | 2 + config/locales/simple_form.he.yml | 2 + config/locales/simple_form.hu.yml | 2 + config/locales/simple_form.is.yml | 2 + config/locales/simple_form.lt.yml | 25 +++- config/locales/simple_form.nl.yml | 2 + config/locales/simple_form.nn.yml | 1 + config/locales/simple_form.pl.yml | 2 + config/locales/simple_form.pt-PT.yml | 2 + config/locales/simple_form.sr-Latn.yml | 2 + config/locales/simple_form.sr.yml | 2 + config/locales/simple_form.th.yml | 3 + config/locales/simple_form.tr.yml | 2 + config/locales/simple_form.vi.yml | 2 + config/locales/simple_form.zh-CN.yml | 2 + config/locales/simple_form.zh-TW.yml | 2 + 32 files changed, 338 insertions(+), 34 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 25aeea9b46..ea67d217da 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -318,7 +318,7 @@ "follow_suggestions.personalized_suggestion": "Suggeriment personalitzat", "follow_suggestions.popular_suggestion": "Suggeriment popular", "follow_suggestions.popular_suggestion_longer": "Popular a {domain}", - "follow_suggestions.similar_to_recently_followed_longer": "Semblant a perfils que seguiu fa poc", + "follow_suggestions.similar_to_recently_followed_longer": "Semblant a perfils que seguiu de fa poc", "follow_suggestions.view_all": "Mostra-ho tot", "follow_suggestions.who_to_follow": "A qui seguir", "followed_tags": "Etiquetes seguides", @@ -473,6 +473,7 @@ "notification.follow": "{name} et segueix", "notification.follow_request": "{name} ha sol·licitat de seguir-te", "notification.mention": "{name} t'ha esmentat", + "notification.moderation-warning.learn_more": "Per a saber-ne més", "notification.moderation_warning": "Heu rebut un avís de moderació", "notification.moderation_warning.action_delete_statuses": "S'han eliminat algunes de les vostres publicacions.", "notification.moderation_warning.action_disable": "S'ha desactivat el vostre compte.", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 5a5031fd14..bae714b1d2 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -298,7 +298,7 @@ "filter_modal.select_filter.title": "Suodata tämä julkaisu", "filter_modal.title.status": "Suodata julkaisu", "filtered_notifications_banner.mentions": "{count, plural, one {maininta} other {mainintaa}}", - "filtered_notifications_banner.pending_requests": "Sinulle on ilmoituksia mahdollisesti tuntemiltasi henkilöiltä seuraavasti: {count, plural, =0 {Ei keltään} one {Yhdeltä henkilöltä} other {# henkilöltä}}", + "filtered_notifications_banner.pending_requests": "Ilmoituksia {count, plural, =0 {ei ole} one {1 henkilöltä} other {# henkilöltä}}, jonka saatat tuntea", "filtered_notifications_banner.title": "Suodatetut ilmoitukset", "firehose.all": "Kaikki", "firehose.local": "Tämä palvelin", @@ -308,7 +308,7 @@ "follow_requests.unlocked_explanation": "Vaikkei tiliäsi ole lukittu, palvelimen {domain} ylläpito on arvioinut, että saatat olla halukas tarkistamaan nämä seuraamispyynnöt erikseen.", "follow_suggestions.curated_suggestion": "Ehdotus ylläpidolta", "follow_suggestions.dismiss": "Älä näytä uudelleen", - "follow_suggestions.featured_longer": "Käsin valinnut palvelimen {domain} tiimi", + "follow_suggestions.featured_longer": "Valinnut käsin palvelimen {domain} tiimi", "follow_suggestions.friends_of_friends_longer": "Suosittu seuraamiesi ihmisten keskuudessa", "follow_suggestions.hints.featured": "Tämän profiilin on valinnut palvelimen {domain} tiimi.", "follow_suggestions.hints.friends_of_friends": "Seuraamasi käyttäjät suosivat tätä profiilia.", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 546b9b7552..083a922012 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -143,7 +143,7 @@ "compose.published.open": "Atidaryti", "compose.saved.body": "Įrašas išsaugotas.", "compose_form.direct_message_warning_learn_more": "Sužinoti daugiau", - "compose_form.encryption_warning": "Mastodon įrašai nėra šifruojami nuo galo iki galo. Per Mastodon nesidalyk jokia slapta informacija.", + "compose_form.encryption_warning": "Mastodon įrašai nėra visapusiškai šifruojami. Per Mastodon nesidalyk jokia slapta informacija.", "compose_form.hashtag_warning": "Šis įrašas nebus įtraukta į jokį saitažodį, nes ji nėra vieša. Tik viešų įrašų galima ieškoti pagal saitažodį.", "compose_form.lock_disclaimer": "Tavo paskyra nėra {locked}. Bet kas gali sekti tave ir peržiūrėti tik sekėjams skirtus įrašus.", "compose_form.lock_disclaimer.lock": "užrakinta", @@ -415,6 +415,7 @@ "loading_indicator.label": "Kraunama…", "media_gallery.toggle_visible": "{number, plural, one {Slėpti vaizdą} few {Slėpti vaizdus} many {Slėpti vaizdo} other {Slėpti vaizdų}}", "moved_to_account_banner.text": "Tavo paskyra {disabledAccount} šiuo metu išjungta, nes persikėlei į {movedToAccount}.", + "mute_modal.show_options": "Rodyti parinktis", "navigation_bar.about": "Apie", "navigation_bar.advanced_interface": "Atidaryti išplėstinę žiniatinklio sąsają", "navigation_bar.blocks": "Užblokuoti naudotojai", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 6ae4e162b3..3a7f63206d 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -217,8 +217,19 @@ "domain_block_modal.title": "Заблокувати домен?", "domain_block_modal.you_will_lose_followers": "Усіх ваших підписників з цього сервера буде вилучено.", "domain_block_modal.you_wont_see_posts": "Ви не бачитимете дописів і сповіщень від користувачів на цьому сервері.", + "domain_pill.activitypub_lets_connect": "Це дозволяє вам спілкуватися та взаємодіяти з людьми не лише на Mastodon, але й у різних соціальних додатках.", + "domain_pill.activitypub_like_language": "ActivityPub - це як мова, якою Мастодонт розмовляє з іншими соціальними мережами.", "domain_pill.server": "Сервер", + "domain_pill.their_handle": "Їхня адреса:", + "domain_pill.their_server": "Їхній цифровий дім, де живуть усі їхні пости.", + "domain_pill.their_username": "Їхній унікальний ідентифікатор на їхньому сервері. Ви можете знайти користувачів з однаковими іменами на різних серверах.", "domain_pill.username": "Ім'я користувача", + "domain_pill.whats_in_a_handle": "Що є в адресі?", + "domain_pill.who_they_are": "Оскільки дескриптори вказують, хто це і де він знаходиться, ви можете взаємодіяти з людьми через соціальну мережу платформ на основі .", + "domain_pill.who_you_are": "Оскільки ваш нікнейм вказує, хто ви та де ви, люди можуть взаємодіяти з вами через соціальну мережу платформ на основі .", + "domain_pill.your_handle": "Ваша адреса:", + "domain_pill.your_server": "Ваш цифровий дім, де живуть усі ваші публікації. Не подобається цей? Перенесіть сервери в будь-який час і залучайте своїх підписників.", + "domain_pill.your_username": "Ваш унікальний ідентифікатор на цьому сервері. Ви можете знайти користувачів з однаковими іменами на різних серверах.", "embed.instructions": "Вбудуйте цей допис до вашого вебсайту, скопіювавши код нижче.", "embed.preview": "Ось який вигляд це матиме:", "emoji_button.activity": "Діяльність", @@ -286,6 +297,7 @@ "filter_modal.select_filter.subtitle": "Використати наявну категорію або створити нову", "filter_modal.select_filter.title": "Фільтрувати цей допис", "filter_modal.title.status": "Фільтрувати допис", + "filtered_notifications_banner.mentions": "{count, plural, one {mention} other {mentions}}", "filtered_notifications_banner.pending_requests": "Сповіщення від {count, plural, =0 {жодної особи} one {однієї особи} few {# осіб} many {# осіб} other {# особи}}, котрих ви можете знати", "filtered_notifications_banner.title": "Відфільтровані сповіщення", "firehose.all": "Всі", @@ -296,6 +308,8 @@ "follow_requests.unlocked_explanation": "Хоча ваш обліковий запис не заблоковано, персонал {domain} припускає, що, можливо, ви хотіли б переглянути ці запити на підписку.", "follow_suggestions.curated_suggestion": "Відібрано командою", "follow_suggestions.dismiss": "Більше не показувати", + "follow_suggestions.featured_longer": "Вибрано командою {domain} вручну", + "follow_suggestions.friends_of_friends_longer": "Популярні серед людей, за якими ви слідкуєте", "follow_suggestions.hints.featured": "Цей профіль був обраний командою {domain}.", "follow_suggestions.hints.friends_of_friends": "Цей профіль популярний серед тих людей, на яких ви підписані.", "follow_suggestions.hints.most_followed": "За цим профілем один з найпопулярніших на {domain}.", @@ -303,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Цей профіль схожий на профілі, за якими ви стежили останнім часом.", "follow_suggestions.personalized_suggestion": "Персоналізована пропозиція", "follow_suggestions.popular_suggestion": "Популярна пропозиція", + "follow_suggestions.popular_suggestion_longer": "Популярно на {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Схожі на профілі, за якими ви нещодавно стежили", "follow_suggestions.view_all": "Переглянути все", "follow_suggestions.who_to_follow": "На кого підписатися", "followed_tags": "Відстежувані хештеґи", @@ -457,12 +473,23 @@ "notification.follow": "{name} підписалися на вас", "notification.follow_request": "{name} відправили запит на підписку", "notification.mention": "{name} згадали вас", + "notification.moderation-warning.learn_more": "Дізнатися більше", + "notification.moderation_warning": "Ви отримали попередження модерації", + "notification.moderation_warning.action_delete_statuses": "Деякі з ваших дописів було видалено.", + "notification.moderation_warning.action_disable": "Ваш обліковий запис було вимкнено.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Деякі з ваших дописів були позначені як чутливі.", + "notification.moderation_warning.action_none": "Ваш обліковий запис отримав попередження модерації.", + "notification.moderation_warning.action_sensitive": "Відтепер ваші дописи будуть позначені як чутливі.", + "notification.moderation_warning.action_silence": "Ваш обліковий запис було обмежено.", + "notification.moderation_warning.action_suspend": "Ваш обліковий запис було заблоковано.", "notification.own_poll": "Ваше опитування завершилося", "notification.poll": "Опитування, у якому ви голосували, скінчилося", "notification.reblog": "{name} поширює ваш допис", "notification.relationships_severance_event": "Втрачено з'єднання з {name}", "notification.relationships_severance_event.account_suspension": "Адміністратор з {from} призупинив {target}, що означає, що ви більше не можете отримувати оновлення від них або взаємодіяти з ними.", + "notification.relationships_severance_event.domain_block": "Адміністратор з {from} заблокував {target}, включаючи {followersCount} ваших підписників і {{followingCount, plural, one {# account} other {# accounts}}, на які ви підписані.", "notification.relationships_severance_event.learn_more": "Дізнатися більше", + "notification.relationships_severance_event.user_domain_block": "Ви заблокували {target}, видаливши {followersCount} ваших підписників і {followingCount, plural, one {# account} other {# accounts}}, за якими ви стежите.", "notification.status": "{name} щойно дописує", "notification.update": "{name} змінює допис", "notification_requests.accept": "Прийняти", @@ -504,9 +531,13 @@ "notifications.permission_required": "Сповіщення на стільниці не доступні, оскільки необхідний дозвіл не надано.", "notifications.policy.filter_new_accounts.hint": "Створено впродовж {days, plural, one {одного} few {# днів} many {# днів} other {# дня}}", "notifications.policy.filter_new_accounts_title": "Нові облікові записи", + "notifications.policy.filter_not_followers_hint": "Включаючи людей, які стежать за вами менше {days, plural, one {one day} other {# days}}", "notifications.policy.filter_not_followers_title": "Люди не підписані на вас", "notifications.policy.filter_not_following_hint": "Доки ви не схвалюєте їх вручну", "notifications.policy.filter_not_following_title": "Люди, на яких ви не підписані", + "notifications.policy.filter_private_mentions_hint": "Відфільтровується, якщо це не відповідь на вашу власну згадку або якщо ви відстежуєте відправника", + "notifications.policy.filter_private_mentions_title": "Небажані приватні згадки", + "notifications.policy.title": "Відфільтрувати сповіщення від…", "notifications_permission_banner.enable": "Увімкнути сповіщення стільниці", "notifications_permission_banner.how_to_control": "Щоб отримувати сповіщення, коли Mastodon не відкрито, увімкніть сповіщення стільниці. Ви можете контролювати, які типи взаємодій створюють сповіщення через кнопку {icon} вгорі після їхнього увімкнення.", "notifications_permission_banner.title": "Не проґавте нічого", diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index 5687507818..b365668210 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -21,6 +21,7 @@ ia: confirmation_instructions: action: Verificar adresse de e-mail action_with_app: Confirmar e retornar a %{app} + subject: 'Mastodon: Instructiones de confirmation pro %{instance}' title: Verificar adresse de e-mail email_changed: explanation: 'Le adresse de e-mail pro tu conto essera cambiate a:' @@ -32,6 +33,7 @@ ia: title: Contrasigno cambiate reconfirmation_instructions: explanation: Confirma le nove adresse pro cambiar tu email. + subject: 'Mastodon: Confirmar e-mail pro %{instance}' title: Verificar adresse de e-mail reset_password_instructions: action: Cambiar contrasigno diff --git a/config/locales/doorkeeper.lt.yml b/config/locales/doorkeeper.lt.yml index 847f41e816..5be291bf89 100644 --- a/config/locales/doorkeeper.lt.yml +++ b/config/locales/doorkeeper.lt.yml @@ -64,7 +64,7 @@ lt: review_permissions: Peržiūrėti leidimus title: Reikalingas leidimas show: - title: Nukopijuok šį įgaliojimo kodą ir įklijuok jį į programėlę. + title: Nukopijuok šį tapatybės patvirtinimo kodą ir įklijuok jį į programėlę. authorized_applications: buttons: revoke: Naikinti @@ -126,7 +126,7 @@ lt: blocks: Blokavimai bookmarks: Žymės conversations: Pokalbiai - crypto: Galo iki galo užšifravimas + crypto: Visapusis šifravimas favourites: Mėgstami filters: Filtrai follow: Sekimai, nutildymai ir blokavimai @@ -163,8 +163,8 @@ lt: admin:write:email_domain_blocks: atlikti prižiūrėjimo veiksmus su el. laiško domenų blokavimais admin:write:ip_blocks: atlikti prižiūrėjimo veiksmus su IP blokavimais admin:write:reports: atlikti paskyrų prižiūrėjimo veiksmus atsakaitams - crypto: naudoti galo iki galo šifravimą - follow: modifikuoti paskyros santykius + crypto: naudoti visapusį šifravimą + follow: modifikuoti paskyros sąryšius push: gauti tavo stumiamuosius pranešimus read: skaityti tavo visus paskyros duomenis read:accounts: matyti paskyrų informaciją diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 85d7c0ed85..193f2b0d59 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -740,9 +740,18 @@ ia: title: Require que nove usatores solve un CAPTCHA pro confirmar lor conto content_retention: danger_zone: Zona periculose + preamble: Controlar como contento generate per le usator es immagazinate in Mastodon. + title: Retention de contento + default_noindex: + desc_html: Affice tote le usatores qui non ha cambiate iste parametro per se mesme + title: Refusar de ordinario le indexation del usatores per le motores de recerca discovery: + follow_recommendations: Sequer le recommendationes + preamble: Presentar contento interessante es instrumental in introducer nove usatores qui pote non cognoscer alcuno de Mastodon. profile_directory: Directorio de profilos public_timelines: Chronologias public + publish_discovered_servers: Publicar servitores discoperite + publish_statistics: Publicar statistica title: Discoperi trends: Tendentias domain_blocks: @@ -750,18 +759,27 @@ ia: disabled: A necuno users: A usators local in session registrations: + moderation_recommandation: Per favor verifica que tu ha un adequate e reactive equipa de moderation ante que tu aperi registrationes a quicunque! + preamble: Controla qui pote crear un conto sur tu servitor. title: Registrationes registrations_mode: modes: + approved: Approbation necessari pro le inscription none: Nemo pote inscriber se open: Quicunque pote inscriber se + warning_hint: Nos consilia usar “Approbation necessari pro le inscription” si tu non crede que tu equipa de moderation pote tractar spam e registrationes maligne in un modo opportun. security: + authorized_fetch: Require authentication ab servitores federate authorized_fetch_hint: Requirer authentication de servitores federate permitte un application plus stricte de blocadas a nivello de usator e de servitor. Nonobstante, isto diminue le prestationes del servitor, reduce le portata de tu responsas e pote introducer problemas de compatibilitate con certe servicios federate. In plus, isto non impedira le actores dedicate a recuperar tu messages public e tu contos. + authorized_fetch_overridden_hint: Tu actualmente non pote cambiar iste parametros perque il es superate per un variabile de ambiente. + federation_authentication: Application del authentication de federation title: Parametros de servitor site_uploads: delete: Deler file incargate destroyed_msg: Incarga de sito delite con successo! software_updates: + critical_update: Critic! Actualisa tosto + description: Il es recommendate de mantener actualisate tu installation de Mastodon pro beneficiar del ultime reparationes e functiones. In ultra, il es aliquando critic actualisar Mastodon in maniera opportun pro evitar problemas de securitate. Pro iste rationes, Mastodon controla pro actualisationes cata 30 minutas, e te notificara secundo tu preferentias de notificationes per email. documentation_link: Pro saper plus release_notes: Notas de version title: Actualisationes disponibile @@ -769,11 +787,15 @@ ia: types: major: Version major minor: Version minor + patch: 'Version de pecias: remedios de bugs e cambiamentos facile a applicar' version: Version statuses: account: Autor application: Application + back_to_account: Retro al pagina de conto + back_to_report: Retro al pagina de reporto batch: + remove_from_report: Remover ab reporto report: Reporto deleted: Delite favourites: Favoritos @@ -783,8 +805,10 @@ ia: media: title: Medios metadata: Metadatos + no_status_selected: Nulle messages era cambiate perque necun era seligite open: Aperir message original_status: Message original + reblogs: Promotiones status_changed: Messages cambiate title: Messages del conto trending: Tendentias @@ -803,35 +827,127 @@ ia: appeal_pending: Appello pendente appeal_rejected: Appello rejectate system_checks: + database_schema_check: + message_html: Il ha migrationes de base de datos pendente. Per favor exeque los pro assecurar que le application se comporta como expectate + elasticsearch_health_red: + message_html: Le aggregation Elasticsearch es malsan (stato rubie), le functiones de recerca es indisponibile + elasticsearch_health_yellow: + message_html: Le aggregation Elasticsearch es malsan (stato jalne), tu poterea voler investigar le ration + elasticsearch_index_mismatch: + message_html: Le mappas de indice Elasticsearch es obsolete. Per favor exeque tootctl search deploy --only=%{value} elasticsearch_preset: action: Vide documentation + message_html: Tu aggregation Elasticsearch ha plus que un nodo, ma Mastodon non es configurate a usar los. elasticsearch_preset_single_node: action: Vide documentation + message_html: Tu aggregation Elasticsearch ha un sol nodo, ES_PRESET deberea esser predefinite a single_node_cluster. + elasticsearch_reset_chewy: + message_html: Le indexation de tu systema Elasticsearch es obsolete per un cambio de configuration. Per cfavor exeque tootctl search deploy --reset-chewy pro actualisar lo. + elasticsearch_running_check: + message_html: Impossibile connecter se a Elasticsearch. Verifica que illo flue, o disactiva le recerca a plen texto + elasticsearch_version_check: + message_html: 'Version de Elasticsearch incompatibile: %{value}' + version_comparison: Elasticsearch %{running_version} es currente dum %{required_version} es necesse rules_check: action: Gerer le regulas del servitor + message_html: Tu non ha definite ulle regulas de servitor. + sidekiq_process_check: + message_html: Nulle processo Sidekiq currente pro le %{value} cauda(s). Controla tu configuration de Sidekiq software_version_critical_check: action: Vider le actualisationes disponibile message_html: Un actualisation critic de Mastodon es disponibile, actualisa lo le plus rapide possibile. software_version_patch_check: action: Vider le actualisationes disponibile + message_html: Un actualisation de remedio de bug pro Mastodon es disponibile. upload_check_privacy_error: action: Verifica hic pro plus de information + message_html: "Tu servitor de web es mal-configurate. Le confidentialitate de tu usatores es a risco." upload_check_privacy_error_object_storage: action: Verifica hic pro plus de information + message_html: "Tu immagazinage de objectos es mal-configurate. Le confidentialitate de tu usatores es a risco." + tags: + review: Revide le stato + updated_msg: Parametros de hashtag actualisate con successo + title: Administration trends: + allow: Permitter approved: Approbate + disallow: Impedir + links: + allow: Permitter ligamine + allow_provider: Permitter editor + description_html: Istos es ligamines que es actualmente multo compartite per contos de que tu servitor vide messages. Illo pote adjutar tu usatores a discoperir lo que eveni in le mundo. Nulle ligamines es monstrate publicamente usque tu non approba le editor. Tu alsi pote permitter o rejectar ligamines singule. + disallow: Impedir ligamine + disallow_provider: Impedir editor + no_link_selected: Nulle ligamine era cambiate perque nulle era seligite + publishers: + no_publisher_selected: Nulle editores era cambiate perque nemo era seligite + shared_by_over_week: + one: Compartite per un persona le septimana passate + other: Compartite per %{count} personas le septimana passate + title: Ligamines de tendentia + not_allowed_to_trend: Non permittite haber tendentia + only_allowed: Solo permittite + pending_review: Attende revision + preview_card_providers: + allowed: Ligamines ab iste editor pote haber tendentia + description_html: Il ha dominios ab que ligamines es sovente compartite sur tu servitor. Ligamines non habera publicamente tendentia salvo que le dominio del ligamine es approbate. Tu approbation (o rejection) se extende al sub-dominios. + rejected: Ligamines ab iste editor non habera tendentia + title: Editores rejected: Rejectate + statuses: + allow: Permitter message + allow_account: Permitter autor + description_html: Istos es messages que tu servitor cognosce perque illos es al momento multo compartite e favorite. Isto pote adjutar tu nove e renovate usatores a trovar altere personas a sequer. Nulle messages es monstrate publicamente usque tu approba le autor, e le autor permitte que su conto es suggerite a alteres. Tu alsi pote permitter o rejectar messages singule. + disallow: Impedir message + disallow_account: Impedir autor + no_status_selected: Nulle messages era cambiate perque nulle era seligite + not_discoverable: Le autor non ha optate pro esser detectabile + shared_by: + one: Compartite e favorite un tempore + other: Compartite e favorite %{friendly_count} tempores + title: Messages de tendentia tags: + current_score: Punctuage actual %{score} + dashboard: + tag_accounts_measure: usos unic + tag_languages_dimension: Linguas principal + tag_servers_dimension: Servitores principal + tag_servers_measure: servitores differente + tag_uses_measure: usos total + listable: Pote esser suggerite + no_tag_selected: Nulle placas era cambiate perque nulle era seligite + not_listable: Non sera suggerite + not_trendable: Non apparera sub tendentias not_usable: Non pote esser usate + peaked_on_and_decaying: Habeva un picco %{date}, ora decade + title: Hashtags de tendentia + trendable: Pote apparer sub tendentias + trending_rank: 'De tendentia #%{rank}' + usable: Pote esser usate + usage_comparison: Usate %{today} vices hodie, al contrario del %{yesterday} de heri + used_by_over_week: + one: Usate per un persona le ultime septimana + other: Usate per %{count} personas le ultime septimana title: Tendentias + trending: Tendentias warning_presets: add_new: Adder nove delete: Deler + edit_preset: Rediger aviso predefinite + empty: Tu non ha ancora definite alcun avisos predefinite. + title: Gerer avisos predefinite webhooks: + add_new: Adder terminal delete: Deler disable: Disactivar disabled: Disactivate + edit: Rediger terminal enable: Activar + enabled: Active + enabled_events: + one: 1 evento activate + other: "%{count} eventos activate" events: Eventos status: Stato admin_mailer: @@ -839,11 +955,19 @@ ia: subject: Actualisationes critic de Mastodon es disponibile pro %{instance}! new_software_updates: subject: Nove versiones de Mastodon es disponibile pro %{instance}! + aliases: + add_new: Crear alias appearance: advanced_web_interface: Interfacie web avantiate + confirmation_dialogs: Dialogos de confirmation + discovery: Discoperta + localization: + guide_link: https://crowdin.com/project/mastodon + guide_link_text: Totes pote contribuer. sensitive_content: Contento sensibile application_mailer: notification_preferences: Cambiar preferentias de e-mail + salutation: "%{name}," settings: 'Cambiar preferentias de e-mail: %{link}' unsubscribe: Desubscriber view: 'Vider:' @@ -853,25 +977,65 @@ ia: created: Application create con successo destroyed: Application delite con successo logout: Clauder le session + regenerate_token: Regenerar testimonio de accesso + token_regenerated: Testimonio de accesso regenerate con successo + warning: Sia multo attente con iste datos. Jammais compartir los con quicunque! + your_token: Tu testimonio de accesso auth: + apply_for_account: Peter un conto + captcha_confirmation: + hint_html: Justo un altere cosa! Nos debe confirmar que tu es un human (isto es assi proque nos pote mantener foras le spam!). Solve le CAPTCHA infra e clicca "Continuar". + title: Controlo de securitate confirmations: + awaiting_review_title: Tu registration es revidite + clicking_this_link: cliccante iste ligamine + login_link: acceder + proceed_to_login_html: Ora tu pote continuar a %{login_link}. welcome_title: Benvenite, %{name}! delete_account: Deler le conto + description: + prefix_sign_up: Inscribe te sur Mastodon hodie! + didnt_get_confirmation: Non recipeva tu un ligamine de confirmation? + dont_have_your_security_key: Non ha tu le clave de securitate? + forgot_password: Contrasigno oblidate? + invalid_reset_password_token: Pete un nove. + link_to_webauth: Usa tu apparato clave de securitate + log_in_with: Accede con + login: Accede logout: Clauder le session + migrate_account: Move a un conto differente + or_log_in_with: O accede con progress: + confirm: Confirma le email details: Tu detalios + review: Nostre revision + rules: Accepta le regulas + providers: + cas: CAS + saml: SAML + register: Inscribe te + resend_confirmation: Reinviar ligamine de confirmation + reset_password: Remontar le contrasigno + rules: + accept: Acceptar + back: Retro + title: Alcun regulas base. + security: Securitate set_new_password: Definir un nove contrasigno status: account_status: Stato del conto view_strikes: Examinar le admonitiones passate contra tu conto challenge: invalid_password: Contrasigno non valide + prompt: Confirma le contrasigno pro continuar deletes: + confirm_password: Insere tu contrasigno actual pro verificar tu identitate proceed: Deler le conto success_msg: Tu conto esseva delite con successo warning: data_removal: Tu messages e altere datos essera removite permanentemente email_change_html: Tu pote cambiar tu adresse de e-mail sin deler tu conto + username_available: Tu nomine de usator essera disponibile novemente disputes: strikes: action_taken: Action prendite @@ -908,6 +1072,7 @@ ia: errors: '422': content: Le verification de securitate ha fallite. Bloca tu le cookies? + title: Falleva le verification de securitate existing_username_validator: not_found_multiple: non poteva trovar %{usernames} exports: @@ -937,6 +1102,9 @@ ia: title: Modificar filtro index: delete: Deler + statuses: + one: "%{count} message" + other: "%{count} messages" title: Filtros new: save: Salveguardar nove filtro @@ -970,6 +1138,7 @@ ia: blocking: Importation de contos blocate bookmarks: Importation de marcapaginas domain_blocking: Importation de dominios blocate + following: Importation de contos sequite lists: Importation de listas muting: Importation de contos silentiate type: Typo de importation @@ -993,6 +1162,7 @@ ia: '604800': 1 septimana '86400': 1 die expires_in_prompt: Nunquam + title: Invitar personas login_activities: authentication_methods: password: contrasigno @@ -1137,6 +1307,7 @@ ia: warning: appeal: Submitter un appello subject: + disable: Tu conto %{acct} ha essite gelate none: Advertimento pro %{acct} sensitive: Tu messages sur %{acct} essera marcate como sensibile a partir de ora silence: Tu conto %{acct} ha essite limitate diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 3449f1d5d7..35111ad396 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -428,9 +428,12 @@ lt: title: Naujas el pašto juodojo sąrašo įtraukimas title: El pašto juodasis sąrašas instances: + back_to_all: Visi by_domain: Domenas content_policies: reason: Viešoji priežastis + delivery: + all: Visi delivery_available: Pristatymas galimas moderation: all: Visi @@ -537,6 +540,8 @@ lt: delete: Ištrinti edit_preset: Keisti įspėjimo nustatymus title: Valdyti įspėjimo nustatymus + webhooks: + events: Įvykiai admin_mailer: auto_close_registrations: body: Dėl pastarojo meto peržiūrėtojų aktyvumo trūkumo %{instance} registracija buvo automatiškai pakeista į reikalaujančią rankinės būdo peržiūros, kad %{instance} nebūtų naudojama kaip platforma potencialiems blogiems veikėjams. Bet kuriuo metu gali ją vėl perjungti į atvirą registraciją. @@ -546,9 +551,15 @@ lt: body_remote: Kažkas iš %{domain} parašė skundą apie %{target} subject: Naujas skundas %{instance} (#%{id}) appearance: + advanced_web_interface: Išplėstinė žiniatinklio sąsaja + advanced_web_interface_hint: 'Jei nori išnaudoti visą ekrano plotį, išplėstinė žiniatinklio sąsaja leidžia sukonfigūruoti daug skirtingų stulpelių, kad vienu metu matytum tiek informacijos, kiek tik nori: Pagrindinis, pranešimai, federacinė laiko skalė, bet kokie sąrašai ir saitažodžiai.' + animations_and_accessibility: Animacijos ir pritaikymas neįgaliesiems + confirmation_dialogs: Patvirtinimo dialogai + discovery: Atradimas localization: body: Mastodon verčia savanoriai. guide_link_text: Visi gali prisidėti. + sensitive_content: Jautrus turinys application_mailer: notification_preferences: Keisti el. pašto nuostatas settings: 'Keisti el. pašto nuostatas: %{link}' @@ -581,6 +592,7 @@ lt: security: Apsauga set_new_password: Nustatyti naują slaptažodį status: + account_status: Paskyros būsena redirecting_to: Tavo paskyra yra neaktyvi, nes šiuo metu ji nukreipiama į %{acct}. self_destruct: Kadangi %{domain} uždaromas, turėsi tik ribotą prieigą prie savo paskyros. view_strikes: Peržiūrėti ankstesnius savo paskyros pažeidimus @@ -611,13 +623,15 @@ lt: your_appeal_approved: Tavo apeliacija buvo patvirtinta your_appeal_pending: Pateikei apeliaciją your_appeal_rejected: Tavo apeliacija buvo atmesta + edit_profile: + hint_html: "Tinkink tai, ką žmonės mato tavo viešame profilyje ir šalia įrašų. Kiti žmonės labiau linkę sekti atgal ir bendrauti su tavimi, jei tavo profilis yra užpildytas ir turi profilio nuotrauką." errors: '403': Jūs neturie prieigos matyti šiam puslapiui. '404': Puslapis nerastas. '410': Puslapis neegzistuoja. '422': - content: Apsaugos patvirtinmas klaidingas. Ar jūs blokuojate sausainius? - title: Apsaugos patvirtinimas nepavyko + content: Nepavyko saugumo patvirtinimas. Ar blokuoji slapukus? + title: Nepavyko saugumo patvirtinimas '429': Stabdomas '500': content: Atsiprašome, tačiau mūsų pusėje įvyko klaida. @@ -638,6 +652,7 @@ lt: storage: Medijos sandėlis featured_tags: add_new: Pridėti naują + hint_html: "Savo profilyje parodyk svarbiausius saitažodžius. Tai puikus įrankis kūrybiniams darbams ir ilgalaikiams projektams sekti, todėl svarbiausios saitažodžiai rodomi matomoje vietoje profilyje ir leidžia greitai pasiekti tavo paties įrašus." filters: contexts: home: Namų laiko juosta @@ -654,8 +669,10 @@ lt: new: title: Pridėti naują filtrą generic: + all: Visi changes_saved_msg: Pakeitimai sėkmingai išsaugoti! copy: Kopijuoti + order_by: Tvarkyti pagal save_changes: Išsaugoti pakeitimus imports: modes: @@ -686,10 +703,10 @@ lt: invalid: Šis kvietimas negalioja. invited_by: 'Jus pakvietė:' max_uses: - few: "%{count} panaudojimai" - many: "%{count} panaudojimo" - one: 1 panaudojimas - other: "%{count} panaudojimų" + few: "%{count} naudojimai" + many: "%{count} naudojimo" + one: 1 naudojimas + other: "%{count} naudojimų" max_uses_prompt: Nėra limito prompt: Generuok ir bendrink nuorodas su kitais, kad suteiktum prieigą prie šio serverio table: @@ -727,6 +744,9 @@ lt: body: 'Tavo įrašą pakėlė %{name}:' subject: "%{name} pakėlė tavo įrašą" title: Naujas pakėlimas + notifications: + email_events: Įvykiai, skirti el. laiško pranešimams + email_events_hint: 'Pasirink įvykius, apie kuriuos nori gauti pranešimus:' pagination: newer: Naujesnis next: Kitas @@ -738,9 +758,30 @@ lt: public_timelines: Viešieji laiko skalės privacy: hint_html: "Tikrink, kaip nori, kad tavo profilis ir įrašai būtų randami. Įjungus įvairias Mastodon funkcijas, jos gali padėti pasiekti platesnę auditoriją. Akimirką peržiūrėk šiuos nustatymus, kad įsitikintum, jog jie atitinka tavo naudojimo būdą." + privacy: Privatumas + privacy_hint_html: Valdyk, kiek informacijos norėtum atskleisti kitų labui. Žmonės atranda įdomių profilių ir šaunių programėlių, naršydami kitų žmonių sekamus profilius ir žiūrėdami, iš kokių programėlių jie skelbia įrašus, bet tu galbūt norėsi tai slėpti. + reach: Pasiekiamumas + reach_hint_html: Valdyk, ar norėtum, kad tave atrastų ir sektų nauji žmonės. Ar nori, kad įrašai būtų rodomi Naršyti ekrane? Ar nori, kad kiti žmonės tave matytų savo sekimo rekomendacijose? Ar nori automatiškai priimti visus naujus sekėjus, ar detaliai valdyti kiekvieną iš jų? + search: Paieška + search_hint_html: Valdyk, kaip norėtum būti surastas. Ar nori, kad žmonės tave rastų pagal tai, apie ką viešai paskelbi? Ar nori, kad ne Mastodon žmonės, ieškantys profilio internete, rastų tavo profilį? Atmink, kad visiško pašalinimo iš visų paieškos variklių viešai skelbiamai informacijai užtikrinti negalima. + title: Privatumas ir pasiekiamumas + privacy_policy: + title: Privatumo politika redirects: prompt: Jei pasitiki šia nuoroda, spustelėk ją, kad tęstum. title: Palieki %{instance} + relationships: + activity: Paskyros aktyvumas + dormant: Neaktyvus + followers: Sekėjai + following: Sekama + last_active: Paskutinį kartą aktyvus + most_recent: Naujausias + moved: Perkelta + mutual: Bendri + primary: Pirminis + relationship: Sąryšis + status: Paskyros būsena remote_follow: missing_resource: Jūsų paskyros nukreipimo URL nerasta scheduled_statuses: @@ -774,13 +815,17 @@ lt: development: Plėtojimas edit_profile: Keisti profilį export: Informacijos eksportas - featured_tags: Rodomi saitažodžiai(#) + featured_tags: Rodomi saitažodžiai import: Importuoti migrate: Paskyros migracija notifications: El. laiško pranešimai preferences: Nuostatos profile: Viešas profilis + relationships: Sekimai ir sekėjai + severed_relationships: Nutrūkę sąryšiai two_factor_authentication: Dviejų veiksnių autentikacija + severed_relationships: + preamble: Užblokavus domeną arba prižiūrėtojams nusprendus pristabdyti nuotolinio serverio veiklą, gali prarasti sekimus ir sekėjus. Kai taip atsitiks, galėsi atsisiųsti nutrauktų sąryšių sąrašus, kad juos patikrinti ir galbūt importuoti į kitą serverį. statuses: attached: description: 'Pridėta: %{attached}' @@ -795,11 +840,11 @@ lt: show_more: Daugiau visibilities: private: Tik sekėjams - private_long: Rodyti tik sekėjams + private_long: rodyti tik sekėjams public: Viešas - public_long: Visi gali matyti + public_long: visi gali matyti unlisted: Neįtrauktas į sąrašus - unlisted_long: Matyti gali visi, tačiau nėra įtraukti į viešąsias laiko skales + unlisted_long: matyti gali visi, bet nėra išvardyti į viešąsias laiko skales statuses_cleanup: enabled_hint: Automatiškai ištrina įrašus, kai jie pasiekia nustatytą amžiaus ribą, nebent jie atitinka vieną iš toliau nurodytų išimčių keep_polls_hint: Neištrina jokių tavo apklausų @@ -808,9 +853,9 @@ lt: stream_entries: sensitive_content: Jautrus turinys themes: - contrast: Mastodon (Didelio Kontrasto) - default: Mastodon (Tamsus) - mastodon-light: Mastodon (Šviesus) + contrast: Mastodon (didelis kontrastas) + default: Mastodon (tamsi) + mastodon-light: Mastodon (šviesi) system: Automatinis (naudoti sistemos temą) two_factor_authentication: disable: Išjungti @@ -876,7 +921,7 @@ lt: follows_title: Ką sekti follows_view_more: Peržiūrėti daugiau sekamų žmonių hashtags_subtitle: Naršyk, kas tendencinga per pastarąsias 2 dienas. - hashtags_title: Tendencijos saitažodžiai + hashtags_title: Trendingiausi saitažodžiai hashtags_view_more: Peržiūrėti daugiau tendencingų saitažodžių post_action: Sukurti post_step: Sakyk labas pasauliui tekstu, nuotraukomis, vaizdo įrašais arba apklausomis. @@ -896,9 +941,10 @@ lt: seamless_external_login: Esi prisijungęs (-usi) per išorinę paslaugą, todėl slaptažodžio ir el. pašto nustatymai nepasiekiami. signed_in_as: 'Prisijungta kaip:' verification: - extra_instructions_html: Patarimas: nuoroda tavo svetainėje gali būti nematoma. Svarbi dalis – tai, kas rel="me" neleidžia apsimesti interneto svetainėse, kuriose yra naudotojų sukurto turinio. Vietoj to gali naudoti net nuorodą puslapio antraštėje esančią žymę a, tačiau HTML turi būti pasiekiamas nevykdant JavaScript. + extra_instructions_html: Patarimas: nuoroda tavo svetainėje gali būti nematoma. Svarbi dalis – tai, kad rel="me" neleidžia apsimesti interneto svetainėse, kuriose yra naudotojų sukurto turinio. Vietoj to gali naudoti net nuorodą puslapio antraštėje esančią žymę a, tačiau HTML turi būti pasiekiamas nevykdant JavaScript. + here_is_how: Štai kaip hint_html: "Savo tapatybės patvirtinimas Mastodon skirtas visiems. Remiantis atviraisiais žiniatinklio standartais, dabar ir visam laikui nemokamas. Viskas, ko tau reikia, yra asmeninė svetainė, pagal kurią žmonės tave atpažįsta. Kai iš savo profilio pateiksi nuorodą į šią svetainę, patikrinsime, ar svetainėje yra nuoroda į tavo profilį, ir parodysime vizualinį indikatorių." - instructions_html: Nukopijuok ir įklijuok toliau pateiktą kodą į savo svetainės HTML. Tada į vieną iš papildomų profilio laukų skirtuke „Redaguoti profilį“ įrašyk savo svetainės adresą ir išsaugok pakeitimus. + instructions_html: Nukopijuok ir įklijuok toliau pateiktą kodą į savo svetainės HTML. Tada į vieną iš papildomų profilio laukų skirtuke Redaguoti profilį įrašyk savo svetainės adresą ir išsaugok pakeitimus. verification: Patvirtinimas verified_links: Tavo patikrintos nuorodos webauthn_credentials: diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml index 62c1da55b5..d3dc4b13f1 100644 --- a/config/locales/simple_form.ca.yml +++ b/config/locales/simple_form.ca.yml @@ -77,11 +77,13 @@ ca: warn: Oculta el contingut filtrat darrere d'un avís mencionant el títol del filtre form_admin_settings: activity_api_enabled: Contador de tuts publicats localment, usuaris actius i registres nous en períodes setmanals + app_icon: WEBP, PNG, GIF o JPG. Canvia la icona per defecte de l'app en dispositius mòbils per una de personalitzada. backups_retention_period: Els usuaris poden generar arxius de les seves publicacions per a baixar-los més endavant. Quan tingui un valor positiu, els arxius s'esborraran del vostre emmagatzematge després del nombre donat de dies. bootstrap_timeline_accounts: Aquests comptes es fixaran en la part superior de les recomanacions de seguiment dels nous usuaris. closed_registrations_message: Es mostra quan el registres estan tancats content_cache_retention_period: S'esborraran totes les publicacions d'altres servidors (impulsos i respostes inclosos) passats els dies indicats, sense tenir en consideració les interaccions d'usuaris locals amb aquestes publicacions. Això inclou les publicacions que un usuari local hagi marcat com a favorites. També es perdran, i no es podran recuperar, les mencions privades entre usuaris d'instàncies diferents. Aquest paràmetre està pensat per a instàncies amb un propòsit especial i trencarà les expectatives dels usuaris si s'utilitza en una instància convencional. custom_css: Pots aplicar estils personalitzats en la versió web de Mastodon. + favicon: WEBP, PNG, GIF o JPG. Canvia la icona per defecte de Mastodon a la pestanya del navegador per una de personalitzada. mascot: Anul·la la il·lustració en la interfície web avançada. media_cache_retention_period: El vostre servidor conserva una còpia dels fitxers multimèdia de les publicacions dels usuaris remots. Si s'indica un valor positiu, s'esborraran passats els dies indicats. Si el fitxer es torna a demanar un cop esborrat, es tornarà a baixar si el contingut origen segueix disponible. Per causa de les restriccions en la freqüència amb què es poden demanar les targetes de previsualització d'altres servidors, es recomana definir aquest valor com a mínim a 14 dies, o les targetes de previsualització no s'actualizaran a demanda abans d'aquest termini. peers_api_enabled: Una llista de noms de domini que aquest servidor ha trobat al fedivers. No inclou cap dada sobre si estàs federat amb un servidor determinat, només si el teu en sap res. La fan servir, en un sentit general, serveis que recol·lecten estadístiques sobre la federació. diff --git a/config/locales/simple_form.da.yml b/config/locales/simple_form.da.yml index c9dcd4fa83..0719e26430 100644 --- a/config/locales/simple_form.da.yml +++ b/config/locales/simple_form.da.yml @@ -77,11 +77,13 @@ da: warn: Skjul filtreret indhold bag en advarsel, der nævner filterets titel form_admin_settings: activity_api_enabled: Antal lokalt opslåede indlæg, aktive brugere samt nye tilmeldinger i ugentlige opdelinger + app_icon: WEBP, PNG, GIF eller JPG. Tilsidesætter standard app-ikonet på mobilenheder med et tilpasset ikon. backups_retention_period: Brugere har mulighed for at generere arkiver af deres indlæg til senere downloade. Når sat til positiv værdi, vil disse arkiver automatisk blive slettet fra lagerpladsen efter det angivne antal dage. bootstrap_timeline_accounts: Disse konti fastgøres øverst på nye brugeres følg-anbefalinger. closed_registrations_message: Vises, når tilmeldinger er lukket content_cache_retention_period: Alle indlæg fra andre servere (herunder boosts og besvarelser) slettes efter det angivne antal dage uden hensyn til lokal brugerinteraktion med disse indlæg. Dette omfatter indlæg, hvor en lokal bruger har markeret dem som bogmærker eller favoritter. Private omtaler mellem brugere fra forskellige instanser vil også være tabt og umulige at gendanne. Brugen af denne indstilling er beregnet til særlige formål instanser og bryder mange brugerforventninger ved implementering til almindelig brug. custom_css: Man kan anvende tilpassede stilarter på Mastodon-webversionen. + favicon: WEBP, PNG, GIF eller JPG. Tilsidesætter standard Mastodon favikonet på mobilenheder med et tilpasset ikon. mascot: Tilsidesætter illustrationen i den avancerede webgrænseflade. media_cache_retention_period: Mediefiler fra indlæg oprettet af eksterne brugere er cachet på din server. Når sat til positiv værdi, slettes medier efter det angivne antal dage. Anmodes om mediedata efter de er slettet, gendownloades de, hvis kildeindholdet stadig er tilgængeligt. Grundet begrænsninger på, hvor ofte linkforhåndsvisningskort forespørger tredjeparts websteder, anbefales det at sætte denne værdi til mindst 14 dage, ellers opdateres linkforhåndsvisningskort ikke efter behov før det tidspunkt. peers_api_enabled: En liste med domænenavne, som denne server har stødt på i fediverset. Ingen data inkluderes her om, hvorvidt der fødereres med en given server, blot at din server kender til det. Dette bruges af tjenester, som indsamler generelle føderationsstatistikker. diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index 758d020282..c1056260bb 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -77,11 +77,13 @@ de: warn: Den gefilterten Beitrag hinter einer Warnung, die den Filtertitel beinhaltet, ausblenden form_admin_settings: activity_api_enabled: Anzahl der wöchentlichen Beiträge, aktiven Profile und Registrierungen auf diesem Server + app_icon: WEBP, PNG, GIF oder JPG Überschreibt das Standard-App-Symbol auf mobilen Geräten mit einem benutzerdefinierten Symbol. backups_retention_period: Nutzer*innen haben die Möglichkeit, Archive ihrer Beiträge zu erstellen, die sie später herunterladen können. Wenn ein positiver Wert gesetzt ist, werden diese Archive nach der festgelegten Anzahl von Tagen automatisch aus deinem Speicher gelöscht. bootstrap_timeline_accounts: Diese Konten werden bei den Follower-Empfehlungen für neu registrierte Nutzer*innen oben angeheftet. closed_registrations_message: Wird angezeigt, wenn Registrierungen deaktiviert sind content_cache_retention_period: Sämtliche Beiträge von anderen Servern (einschließlich geteilte Beiträge und Antworten) werden, unabhängig von der Interaktion der lokalen Nutzer*innen mit diesen Beiträgen, nach der festgelegten Anzahl von Tagen gelöscht. Das betrifft auch Beiträge, die von lokalen Nutzer*innen favorisiert oder als Lesezeichen gespeichert wurden. Private Erwähnungen zwischen Nutzer*innen von verschiedenen Servern werden ebenfalls verloren gehen und können nicht wiederhergestellt werden. Das Verwenden dieser Option richtet sich ausschließlich an Server für spezielle Zwecke und wird die allgemeine Nutzungserfahrung beeinträchtigen, wenn sie für den allgemeinen Gebrauch aktiviert ist. custom_css: Du kannst benutzerdefinierte Stile auf die Web-Version von Mastodon anwenden. + favicon: WEBP, PNG, GIF oder JPG überschreibt das Standard-Mastodon favicon mit einem benutzerdefinierten Icon. mascot: Überschreibt die Abbildung in der erweiterten Weboberfläche. media_cache_retention_period: Mediendateien aus Beiträgen von externen Nutzer*innen werden auf deinem Server zwischengespeichert. Wenn ein positiver Wert gesetzt ist, werden die Medien nach der festgelegten Anzahl von Tagen gelöscht. Sollten die Medien nach dem Löschvorgang wieder angefragt werden, werden sie erneut heruntergeladen, sofern der ursprüngliche Inhalt noch vorhanden ist. Es wird empfohlen, diesen Wert auf mindestens 14 Tage festzulegen, da die Häufigkeit der Abfrage von Linkvorschaukarten für Websites von Dritten begrenzt ist und die Linkvorschaukarten sonst nicht vor Ablauf dieser Zeit aktualisiert werden. peers_api_enabled: Eine Liste von Domains, die diesem Server im Fediverse begegnet sind. Hierbei werden keine Angaben darüber gemacht, ob du mit einem bestimmten Server föderierst, sondern nur, dass dein Server davon weiß. Dies wird von Diensten verwendet, die allgemein Statistiken übers Ferdiverse sammeln. diff --git a/config/locales/simple_form.en-GB.yml b/config/locales/simple_form.en-GB.yml index 9aedac15f3..f4668ccada 100644 --- a/config/locales/simple_form.en-GB.yml +++ b/config/locales/simple_form.en-GB.yml @@ -77,12 +77,9 @@ en-GB: warn: Hide the filtered content behind a warning mentioning the filter's title form_admin_settings: activity_api_enabled: Counts of locally published posts, active users, and new registrations in weekly buckets - app_icon: WEBP, PNG, GIF or JPG. Overrides the default app icon on mobile devices with a custom icon. - backups_retention_period: Keep generated user archives for the specified number of days. bootstrap_timeline_accounts: These accounts will be pinned to the top of new users' follow recommendations. closed_registrations_message: Displayed when sign-ups are closed custom_css: You can apply custom styles on the web version of Mastodon. - favicon: WEBP, PNG, GIF or JPG. Overrides the default Mastodon favicon with a custom icon. mascot: Overrides the illustration in the advanced web interface. peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense. profile_directory: The profile directory lists all users who have opted-in to be discoverable. diff --git a/config/locales/simple_form.es-AR.yml b/config/locales/simple_form.es-AR.yml index cd1b681688..e346a23a02 100644 --- a/config/locales/simple_form.es-AR.yml +++ b/config/locales/simple_form.es-AR.yml @@ -77,11 +77,13 @@ es-AR: warn: Ocultar el contenido filtrado detrás de una advertencia mencionando el título del filtro form_admin_settings: activity_api_enabled: Conteos de mensajes publicados localmente, cuentas activas y nuevos registros en tandas semanales + app_icon: WEBP, PNG, GIF o JPG. Reemplaza el ícono de aplicación predeterminado en dispositivos móviles con uno personalizado. backups_retention_period: Los usuarios tienen la capacidad de generar archivos historiales de sus mensajes para descargar más adelante. Cuando se establece un valor positivo, estos archivos se eliminarán automáticamente de su almacenamiento después del número especificado de días. bootstrap_timeline_accounts: Estas cuentas serán fijadas a la parte superior de las recomendaciones de cuentas a seguir para nuevos usuarios. closed_registrations_message: Mostrado cuando los registros están cerrados content_cache_retention_period: Todos los mensajes de otros servidores (incluyendo adhesiones y respuestas) se eliminarán después del número de días especificado, sin tener en cuenta la interacción del usuario local con esos mensajes. Esto incluye mensajes que un usuario local haya agregado a marcadores o los haya marcado como favoritos. Las menciones privadas entre usuarios de diferentes servidores también se perderán y también serán imposibles de restaurar. El uso de esta configuración está destinado a servidores de propósito especial y rompe muchas expectativas de los usuarios cuando se implementa para uso general. custom_css: Podés aplicar estilos personalizados a la versión web de Mastodon. + favicon: WEBP, PNG, GIF o JPG. Reemplaza el favicón predeterminado de Mastodon con uno personalizado. mascot: Reemplaza la ilustración en la interface web avanzada. media_cache_retention_period: Los archivos de medios de mensajes publicados por usuarios remotos se almacenan en la memoria caché en tu servidor. Cuando se establece un valor positivo, los medios se eliminarán después del número especificado de días. Si los datos multimedia se solicitan después de eliminarse, se volverán a descargar, si es que el contenido fuente todavía está disponible. Debido a restricciones en la frecuencia con la que las tarjetas de previsualización de enlace consultan a sitios web de terceros, se recomienda establecer este valor a, al menos, 14 días, o las tarjetas de previsualización de enlaces no se actualizarán a pedido antes de ese momento. peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el Fediverso. Acá no se incluye ningún dato sobre si federás con un servidor determinado, sólo que tu servidor lo conoce. Esto es usado por los servicios que recopilan estadísticas sobre la federación en un sentido general. diff --git a/config/locales/simple_form.eu.yml b/config/locales/simple_form.eu.yml index ba4c9ebcf8..8c467bc9bf 100644 --- a/config/locales/simple_form.eu.yml +++ b/config/locales/simple_form.eu.yml @@ -77,11 +77,13 @@ eu: warn: Ezkutatu iragazitako edukia iragazkiaren izenburua duen abisu batekin form_admin_settings: activity_api_enabled: Lokalki argitaratutako bidalketak, erabiltzaile aktiboak, eta izen-emateen kopuruak astero zenbatzen ditu + app_icon: WEBP, PNG, GIF edo JPG. Aplikazioaren ikono lehenetsia gainidazten du ikono pertsonalizatu batekin gailu mugikorretan. backups_retention_period: Erabiltzaileek geroago deskarga dezaketen beren argitalpenen artxiboak sor ditzakete. Balio positibo bat ezartzean, artxibo hauek biltegiratzetik automatikoki ezabatuko dira zehazturiko egunen buruan. bootstrap_timeline_accounts: Kontu hauek erabiltzaile berrien jarraitzeko gomendioen goiko aldean ainguratuko dira. closed_registrations_message: Izen-ematea itxia dagoenean bistaratua content_cache_retention_period: Beste zerbitzarietako argitalpen guztiak (bultzadak eta erantzunak barne) ezabatuko dira zehazturiko egunen buruan, argitalpen horiek izan ditzaketen erabiltzaile lokalaren interakzioa kontuan izanik gabe. Instantzia desberdinetako erabiltzaileen arteko aipamen pribatuak ere galdu egingo dira eta ezin izango dira berreskuratu. Ezarpen honen erabilera xede berezia duten instantziei zuzendua dago eta erabiltzaileen itxaropena hausten da orotariko erabilerarako inplementatzean. custom_css: Estilo pertsonalizatuak aplikatu ditzakezu Mastodonen web bertsioan. + favicon: WEBP, PNG, GIF or JPG. Mastodon-en favicon-a gainidazten du ikono pertsonalizatu batekin. mascot: Web interfaze aurreratuko ilustrazioa gainidazten du. media_cache_retention_period: Multimedia-fitxategiak dituzten urruneko erabiltzaileen argitalpenak zure zerbitzarian gordetzen dira cachean. Balio positiboa ezartzean, multimedia zehazturiko egunen buruan ezabatuko da. Multimedia-datuak eskatzen badira ezabatu ostean, berriro deskargatuko dira, iturburuko edukia oraindik erabilgarri badago. Estekaren aurrebistako txartelek hirugarrenen guneei zenbatetan dei diezaieketen mugatzen dieten murrizketak direla eta, balio honi, gutxienez, 14 egunen balioa ezartzea gomendatzen da, bestela, esteken aurrebistako txartelak ez dira eguneratuko eskatu ahala denbora horren aurretik. peers_api_enabled: Zerbitzari honek fedibertsoan ikusi dituen zerbitzarien domeinu-izenen zerrenda. Ez da daturik ematen zerbitzari jakin batekin federatzearen ala ez federatzearen inguruan, zerbitzariak haien berri duela soilik. Federazioari buruzko estatistika orokorrak biltzen dituzten zerbitzuek erabiltzen dute hau. diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml index 510b880e3b..4971e25022 100644 --- a/config/locales/simple_form.fi.yml +++ b/config/locales/simple_form.fi.yml @@ -77,10 +77,12 @@ fi: warn: Piilota suodatettu sisältö varoituksen taakse, jossa mainitaan suodattimen nimi form_admin_settings: activity_api_enabled: Paikallisesti julkaistujen julkaisujen, aktiivisten käyttäjien ja rekisteröitymisten viikoittainen määrä + app_icon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen mobiililaitteiden sovelluskuvakkeen omalla kuvakkeella. backups_retention_period: Käyttäjillä on mahdollisuus arkistoida julkaisujaan myöhemmin ladattaviksi. Kun tämä on asetettu positiiviseksi arvoksi, nämä arkistot poistetaan automaattisesti asetetun päivien määrän jälkeen. bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuosituslistojen alkuun. closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu custom_css: Voit käyttää mukautettuja tyylejä Mastodonin verkkoversiossa. + favicon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen Mastodonin suosikkikuvakkeen omalla kuvakkeella. mascot: Ohittaa kuvituksen edistyneessä selainkäyttöliittymässä. peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, oletko liitossa tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja federoinnista yleisellä tasolla. profile_directory: Profiilihakemisto lueteloi kaikki käyttäjät, jotka ovat ilmoittaneet olevansa löydettävissä. diff --git a/config/locales/simple_form.fo.yml b/config/locales/simple_form.fo.yml index c7c0033225..7d4da2b51e 100644 --- a/config/locales/simple_form.fo.yml +++ b/config/locales/simple_form.fo.yml @@ -77,11 +77,13 @@ fo: warn: Fjal filtreraða innihaldið aftan fyri eina ávaring, sum nevnir heitið á filtrinum form_admin_settings: activity_api_enabled: Tal av lokalt útgivnum postum, virknum brúkarum og nýggjum skrásetingum býtt vikuliga + app_icon: WEBP, PNG, GIF ella JPG. Býtir vanligu ikonina á fartelefoneindum um við eina ser-ikon. backups_retention_period: Brúkarar hava møguleika at gera trygdaravrit av teirra postum, sum tey kunnu taka niður seinni. Tá hetta er sett til eitt virði størri enn 0, so verða hesi trygdaravrit strikaði av sær sjálvum frá tínar goymslu eftir ásetta talið av døgum. bootstrap_timeline_accounts: Hesar kontur verða festar ovast á listanum yvir brúkarar, sum tey nýggju verða mælt til at fylgja. closed_registrations_message: Víst tá stongt er fyri tilmeldingum content_cache_retention_period: Allir postar frá øðrum ambætarum (íroknað stimbranir og svar) verða strikaði eftir ásetta talið av døgum, óansæð hvussu lokalir brúkarar hava samvirkað við hesar postar. Hetta fevnir eisini um postar, sum lokalir brúkarar hava bókamerkt ella yndismerkt. Privatar umrøður millum brúkarar frá ymiskum ambætarum verða eisini burturmistar og ómøguligar at endurskapa. Brúk av hesi stillingini er einans hugsað til serligar støður og oyðileggur nógv, sum brúkarar vænta av einum vanligum ambætara. custom_css: Tú kanst seta títt egna snið upp í net-útgávuni av Mastodon. + favicon: WEBP, PNG, GIF ella JPG. Býtir vanligu Mastodon fav-ikonina um við eina ser-ikon. mascot: Skúgvar til viks myndprýðingina í framkomna vev-markamótinum. media_cache_retention_period: Miðlafílur frá postum, sum fjarbrúkarar hava gjørt, verða goymdir á tínum ambætara. Tá hetta er sett til eitt virði størri enn 0, so verða miðlafílurnar strikaðar eftir ásetta talið av døgum. Um miðladátur verða umbidnar eftir at tær eru strikaðar, verða tær tiknar innaftur á ambætaran, um keldutilfarið enn er tøkt. Vegna avmarkingar á hvussu ofta undanvísingarkort til leinki spyrja triðjapartsstøð, so verður mælt til at seta hetta virðið til í minsta lagi 14 dagar. Annars verða umbønir um dagføringar av undanvísingarkortum til leinki ikki gjørdar áðrenn hetta. peers_api_enabled: Ein listi við navnaøkjum, sum hesin ambætarin er komin framat í fediversinum. Ongar dátur eru tiknar við her um tú er sameind/ur við ein givnan ambætara, einans at tín ambætari veit um hann. Hetta verður brúkt av tænastum, sum gera hagtøl um sameining yvirhøvur. diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml index 0433496013..0411c45bc1 100644 --- a/config/locales/simple_form.gl.yml +++ b/config/locales/simple_form.gl.yml @@ -77,11 +77,13 @@ gl: warn: Agochar o contido filtrado tras un aviso que conteña o nome do filtro form_admin_settings: activity_api_enabled: Conta do número de publicacións locais, usuarias activas, e novos rexistros en acumulados semanais + app_icon: WEBP, PNG, GIF ou JPG. Sobrescribe a icona por defecto da aplicación nos dispositivos móbiles cunha icona personalizada. backups_retention_period: As usuarias poden crear arquivos das súas publicacións para descargalos. Cando se establece un valor positivo, estes arquivos serán borrados automáticamente da túa almacenaxe despois do número de días establecido. bootstrap_timeline_accounts: Estas contas aparecerán fixas na parte superior das recomendacións para as usuarias. closed_registrations_message: Móstrase cando non se admiten novas usuarias content_cache_retention_period: Todas as publicacións procedentes de outros servidores (incluído promocións e respostas) van ser eliminadas despois do número de días indicado, sen importar as interaccións das usuarias locais con esas publicacións. Esto inclúe publicacións que a usuaria local marcou como favoritas ou incluíu nos marcadores. As mencións privadas entre usuarias de diferentes instancias tamén se eliminarán e non se poderán restablecer. O uso desta ferramenta esta orientado a situacións especiais e estraga moitas das expectativas das usuarias ao implementala cun propósito de uso xeral. custom_css: Podes aplicar deseños personalizados na versión web de Mastodon. + favicon: WEBP, PNG, GIF ou JPG. Sobrescribe a icona de favoritos de Mastodon por defecto cunha icona personalizada. mascot: Sobrescribe a ilustración na interface web avanzada. media_cache_retention_period: Os ficheiros multimedia de publicacións de usuarias remotas están almacenados no teu servidor. Ao establecer un valor positivo, o multimedia vaise eliminar despois do número de días establecido. Se o multimedia fose requerido após ser eliminado entón descargaríase outra vez, se aínda está dispoñible na orixe. Debido a restricións sobre a frecuencia en que o servizo de vista previa trae recursos de terceiras partes, é recomendable establecer este valor polo menos en 14 días, ou as tarxetas de vista previa non se actualizarán baixo demanda para casos anteriores a ese prazo. peers_api_enabled: Unha lista dos nomes de dominio que este servidor atopou no fediverso. Non se inclúen aquí datos acerca de se estás a federar con eles ou non, só que o teu servidor os recoñeceu. Ten utilidade para servizos que recollen estatísticas acerca da federación nun amplo senso. diff --git a/config/locales/simple_form.he.yml b/config/locales/simple_form.he.yml index 841745dbc0..65c6f6110f 100644 --- a/config/locales/simple_form.he.yml +++ b/config/locales/simple_form.he.yml @@ -77,11 +77,13 @@ he: warn: הסתר את התוכן המסונן מאחורי אזהרה עם כותרת המסנן form_admin_settings: activity_api_enabled: מספר ההודעות שפורסמו מקומית, משתמשים פעילים, והרשמות חדשות בדליים שבועיים + app_icon: WEBP, PNG, GIF או JPG. גובר על אייקון ברירת המחדל ביישומון על מכשירים ניידים ומחליף אותו באייקון נבחר. backups_retention_period: למשתמשים יש יכולת לבקש ארכיון של הודעותיהם להורדה מאוחר יותר. כאשר נבחר ערך חיובי, הארכיונים הללו ימחקו מאחסון לאחר מספר הימים שצוינו. bootstrap_timeline_accounts: חשבונות אלו יוצמדו לראש רשימת המלצות המעקב של משתמשים חדשים. closed_registrations_message: להציג כאשר הרשמות חדשות אינן מאופשרות content_cache_retention_period: כל ההודעות משרתים אחרים (לרבות הדהודים ותגובות) ימחקו אחרי מספר ימים, ללא קשר לאינטראקציה של משתמשים מקומיים איתם. בכלל זה הודעות שהמתשתמשים המקומיים סימנו בסימניה או חיבוב. איזכורים פרטיים ("דיאם") בין משתמשים בין שרתים שונים יאבדו גם הם ולא תהיה אפשרות לשחזרם. השימוש באפשרות הזו מיועד לשרתים עם ייעוד מיוחד ושובר את ציפיותיהם של רב המשתמשים כאשר האפשרות מופעלת בשרת לשימוש כללי. custom_css: ניתן לבחור ערכות סגנון אישיות בגרסת הדפדפן של מסטודון. + favicon: WEBP, PNG, GIF או JPG. גובר על "פאבאייקון" ברירת המחדל ומחליף אותו באייקון נבחר בדפדפן. mascot: בחירת ציור למנשק הווב המתקדם. media_cache_retention_period: קבצי מדיה מהודעות שהגיעו משרתים רחוקים נשמרות על השרת שלך. כאשר יבחר פה מספר חיובי, המדיה תמחק לאחר מספר ימים כמצוין. אם המידע יבוקש שוב לאחר שנמחק, הוא יורד מחדש, אם המידע עדיין זמין בצד הרחוק. עקב מגבלות על תכיפות שליפת כרטיסי קדימון מאתרים מרוחקים, מומלץ לכוון את הערך ל־14 יום לפחות, או שכרטיסי קדימונים לא יעודכנו לפי דרישה לפני חלוף חלון הזמן הזה. peers_api_enabled: רשימת השרתים ששרת זה פגש בפדיוורס. לא כולל מידע לגבי קשר ישיר עם שרת נתון, אלא רק שידוע לשרת זה על קיומו. מידע זה משמש שירותים האוספים סטטיסטיקות כלליות על הפדרציה. diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml index e2040cafd8..8fee5b414d 100644 --- a/config/locales/simple_form.hu.yml +++ b/config/locales/simple_form.hu.yml @@ -77,11 +77,13 @@ hu: warn: A szűrt tartalom a szűrő címét említő figyelmeztetés mögé rejtése form_admin_settings: activity_api_enabled: Helyi bejegyzések, aktív felhasználók és új regisztrációk száma heti bontásban + app_icon: WEBP, PNG, GIF vagy JPG. Mobileszközökön az alkalmazás alapértelmezett ikonját felülírja egy egyéni ikonnal. backups_retention_period: A felhasználók archívumokat állíthatnak elő a bejegyzéseikből, hogy később letöltsék azokat. Ha pozitív értékre van állítva, akkor a megadott számú nap után automatikusan törölve lesznek a tárhelyedről. bootstrap_timeline_accounts: Ezek a fiókok ki lesznek tűzve az új felhasználók követési javaslatainak élére. closed_registrations_message: Akkor jelenik meg, amikor a regisztráció le van zárva content_cache_retention_period: Minden más kiszolgálóról származó bejegyzés (megtolásokkal és válaszokkal együtt) törölve lesz a megadott számú nap elteltével, függetlenül a helyi felhasználók ezekkel a bejegyzésekkel történő interakcióitól. Ebben azok a bejegyzések is benne vannak, melyeket a helyi felhasználó könyvjelzőzött vagy kedvencnek jelölt. A különböző kiszolgálók felhasználói közötti privát üzenetek is el fognak veszni visszaállíthatatlanul. Ennek a beállításnak a használata különleges felhasználási esetekre javasolt, mert számos felhasználói elvárás fog eltörni, ha általános céllal használják. custom_css: A Mastodon webes verziójában használhatsz egyéni stílusokat. + favicon: WEBP, PNG, GIF vagy JPG. Az alapértelmezett Mastodon favicon felülírása egy egyéni ikonnal. mascot: Felülbírálja a speciális webes felületen található illusztrációt. media_cache_retention_period: A távoli felhasználók bejegyzéseinek médiatartalmait a kiszolgálód gyorsítótárazza. Ha pozitív értékre állítják, ezek a médiatartalmak a megadott számú nap után törölve lesznek. Ha a médiát újra lekérik, miután törlődött, újra le fogjuk tölteni, ha az eredeti még elérhető. A hivatkozások előnézeti kártyáinak harmadik fél weboldalai felé történő hivatkozásaira alkalmazott megkötései miatt javasolt, hogy ezt az értéket legalább 14 napra állítsuk, ellenkező esetben a hivatkozások előnézeti kártyái szükség esetén nem fognak tudni frissülni ezen idő előtt. peers_api_enabled: Azon domainek listája, melyekkel ez a kiszolgáló találkozott a fediverzumban. Nem csatolunk adatot arról, hogy föderált kapcsolatban vagy-e az adott kiszolgálóval, csak arról, hogy a kiszolgálód tud a másikról. Ezt olyan szolgáltatások használják, melyek általában a föderációról készítenek statisztikákat. diff --git a/config/locales/simple_form.is.yml b/config/locales/simple_form.is.yml index 6f3072758c..044e24deb0 100644 --- a/config/locales/simple_form.is.yml +++ b/config/locales/simple_form.is.yml @@ -77,11 +77,13 @@ is: warn: Fela síað efni á bakvið aðvörun sem tekur fram titil síunnar form_admin_settings: activity_api_enabled: Fjöldi staðværra stöðufærslna, virkra notenda og nýskráninga í vikulegum skömmtum + app_icon: WEBP, PNG, GIF eða JPG. Tekur yfir sjálfgefna táknmynd forrits á snjalltækjum með sérsniðinni táknmynd. backups_retention_period: Notendur hafa kost á að útbúa safnskrár með færslunum sínum til að sækja svo síðar. Þegar þetta er stillt á jákvætt gildi, verður þessum safnskrám eytt sjáfkrafa eftir þeim tiltekna fjölda daga. bootstrap_timeline_accounts: Þessir notendaaðgangar verða festir efst í meðmælum til nýrra notenda um að fylgjast með þeim. closed_registrations_message: Birtist þegar lokað er á nýskráningar content_cache_retention_period: Öllum færslum af öðrum netþjónum (þar með taldar endurbirtingar og svör) verður eytt eftir uppgefinn fjölda daga, án tillits til gagnvirkni staðværra notenda við þessar færslur. Þetta á einnig við um færslur sem notandinn hefur merkt sem bókamerki eða eftirlæti. Beinar tilvísanir (einkaspjall) milli notenda af mismunandi netþjónum munu einnig tapast og er engin leið til að endurheimta þær. Notkun á þessari stillingu er einungis ætluð sérstilltum netþjónum og mun skemma fyrir notendum ef þetta er sett upp fyrir almenna notkun. custom_css: Þú getur virkjað sérsniðna stíla í vefútgáfu Mastodon. + favicon: WEBP, PNG, GIF eða JPG. Tekur yfir sjálfgefna Mastodon favicon-táknmynd með sérsniðinni táknmynd. mascot: Þetta tekyr yfir myndskreytinguna í ítarlega vefviðmótinu. media_cache_retention_period: Myndefnisskrár úr færslum sem gerðar eru af fjartengdum notendum eru geymdar á netþjóninum þínum. Þegar þetta er stillt á jákvætt gildi, verður þessum skrám eytt sjáfkrafa eftir þeim tiltekna fjölda daga. Ef beðið er um myndefnið eftir að því er eytt, mun það verða sótt aftur ef frumgögnin eru ennþá aðgengileg. Vegna takmarkana á hversu oft forskoðunarspjöld tengla eru sótt á utanaðkomandi netþjóna, þá er mælt með því að setja þetta gildi á að minnsta kosti 14 daga, annars gæti mistekist að uppfæra forskoðunarspjöld tengla eftir þörfum fyrir þann tíma. peers_api_enabled: Listi yfir þau lénaheiti sem þessi netþjónn hefur rekist á í skýjasambandinu. Engin gögn eru hér sem gefa til kynna hvort þú sért í sambandi við tiltekinn netþjón, bara að netþjónninn þinn viti um hann. Þetta er notað af þjónustum sem safna tölfræði um skýjasambönd á almennan hátt. diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index f6a3ad9372..1be95a9f1b 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -40,7 +40,7 @@ lt: defaults: autofollow: Žmonės, kurie užsiregistruos per kvietimą, automatiškai seks tave avatar: WEBP, PNG, GIF arba JPG. Ne daugiau kaip %{size}. Bus sumažintas iki %{dimensions} tšk. - bot: Signalizuoti kitiems, kad paskyroje daugiausia atliekami automatiniai veiksmai ir kad ji gali būti nestebima + bot: Signalizuoti kitiems, kad paskyroje daugiausia atliekami automatiniai veiksmai ir kad ji gali būti nestebima. context: Vienas arba keli kontekstai, kuriems turėtų būti taikomas filtras current_password: Saugumo sumetimais įvesk dabartinės paskyros slaptažodį current_username: Kad patvirtintum, įvesk dabartinės paskyros naudotojo vardą @@ -53,14 +53,14 @@ lt: password: Naudok bent 8 simbolius phrase: Bus suderinta, neatsižvelgiant į teksto lygį arba įrašo turinio įspėjimą scopes: Prie kurių API programai bus leidžiama pasiekti. Pasirinkus aukščiausio lygio sritį, atskirų sričių pasirinkti nereikia. - setting_aggregate_reblogs: Nerodyti naujų pakėlimų įrašams, kurie neseniai buvo pakelti (taikoma tik naujai gautiems pakėlimams) - setting_always_send_emails: Paprastai pranešimai el. paštu nebus siunčiami, kai aktyviai naudoji Mastodon - setting_default_sensitive: Jautrioji medija pagal numatytuosius nustatymus yra paslėpta ir gali būti atskleista paspaudus + setting_aggregate_reblogs: Nerodyti naujų pakėlimų įrašams, kurie neseniai buvo pakelti (taikoma tik naujai gautiems pakėlimams). + setting_always_send_emails: Paprastai el. laiško pranešimai nebus siunčiami, kai aktyviai naudoji Mastodon. + setting_default_sensitive: Jautrioji medija pagal numatytuosius nustatymus yra paslėpta ir gali būti atskleista spustelėjus. setting_display_media_default: Slėpti mediją, pažymėtą kaip jautrią setting_display_media_hide_all: Visada slėpti mediją setting_display_media_show_all: Visada rodyti mediją - setting_use_blurhash: Gradientai pagrįsti paslėptų vaizdų spalvomis, tačiau užgožia bet kokias detales - setting_use_pending_items: Slėpti laiko skalės naujienas po paspaudimo, vietoj automatinio kanalo slinkimo + setting_use_blurhash: Gradientai pagrįsti paslėptų vizualizacijų spalvomis, bet užgožia bet kokias detales. + setting_use_pending_items: Slėpti laiko skalės naujienas po paspaudimo, vietoj automatinio srauto slinkimo. username: Gali naudoti raides, skaičius ir pabraukimus whole_word: Kai raktažodis ar frazė yra tik raidinis ir skaitmeninis, jis bus taikomas tik tada, jei atitiks visą žodį email_domain_block: @@ -76,6 +76,7 @@ lt: activity_api_enabled: Vietinių paskelbtų įrašų, aktyvių naudotojų ir naujų registracijų skaičiai kas savaitę backups_retention_period: Naudotojai gali generuoti savo įrašų archyvus, kuriuos vėliau galės atsisiųsti. Nustačius teigiamą reikšmę, šie archyvai po nurodyto dienų skaičiaus bus automatiškai ištrinti iš saugyklos. content_cache_retention_period: Visi įrašai iš kitų serverių (įskaitant pakėlimus ir atsakymus) bus ištrinti po nurodyto dienų skaičiaus, neatsižvelgiant į bet kokią vietinio naudotojo sąveiką su tais įrašais. Tai taikoma ir tiems įrašams, kuriuos vietinis naudotojas yra pažymėjęs kaip žymes ar mėgstamus. Privačios paminėjimai tarp naudotojų iš skirtingų instancijų taip pat bus prarastos ir jų bus neįmanoma atkurti. Šis nustatymas skirtas naudoti ypatingos paskirties instancijose, o įgyvendinus jį bendram naudojimui, pažeidžiami daugelio naudotojų lūkesčiai. + mascot: Pakeičia išplėstinės žiniatinklio sąsajos iliustraciją. media_cache_retention_period: Nuotolinių naudotojų įrašytų įrašų medijos failai talpinami tavo serveryje. Nustačius teigiamą reikšmę, medijos bus ištrinamos po nurodyto dienų skaičiaus. Jei medijos duomenų bus paprašyta po to, kai jie bus ištrinti, jie bus atsiųsti iš naujo, jei šaltinio turinys vis dar prieinamas. Dėl apribojimų, susijusių su nuorodų peržiūros kortelių apklausos dažnumu trečiųjų šalių svetainėse, rekomenduojama nustatyti šią reikšmę ne trumpesnę kaip 14 dienų, kitaip nuorodų peržiūros kortelės nebus atnaujinamos pagal pareikalavimą iki to laiko. peers_api_enabled: Domenų pavadinimų sąrašas, su kuriais šis serveris susidūrė fediverse. Čia nėra duomenų apie tai, ar tu bendrauji su tam tikru serveriu, tik apie tai, kad tavo serveris apie jį žino. Tai naudojama tarnybose, kurios renka federacijos statistiką bendrąja prasme. site_contact_email: Kaip žmonės gali su tavimi susisiekti teisiniais ar pagalbos užklausimais. @@ -91,11 +92,13 @@ lt: webauthn: Jei tai USB raktas, būtinai jį įkišk ir, jei reikia, paspausk. settings: indexable: Tavo profilio puslapis gali būti rodomas paieškos rezultatuose Google, Bing ir kituose. + show_application: Neatsižvelgiant į tai, visada galėsi matyti, kuri programėlė paskelbė tavo įrašą. user: - chosen_languages: Kai pažymėta, viešose laiko skalėse bus rodomi tik įrašai pasirinktomis kalbomis + chosen_languages: Kai pažymėta, viešose laiko skalėse bus rodomi tik įrašai pasirinktomis kalbomis. role: Vaidmuo valdo, kokius leidimus naudotojas (-a) turi labels: account: + discoverable: Rekomenduoti profilį ir įrašus į atradimo algoritmus indexable: Įtraukti viešus įrašus į paieškos rezultatus show_collections: Rodyti sekimus ir sekėjus profilyje unlocked: Automatiškai priimti naujus sekėjus @@ -118,19 +121,26 @@ lt: note: Biografija password: Slaptažodis phrase: Raktažodis arba frazė + setting_advanced_layout: Įjungti išplėstinę žiniatinklio sąsają + setting_aggregate_reblogs: Grupuoti pakėlimus laiko skalėse + setting_always_send_emails: Visada siųsti el. laiško pranešimus setting_auto_play_gif: Automatiškai leisti animuotų GIF setting_boost_modal: Rodyti patvirtinimo dialogą prieš pakėliant įrašą setting_default_language: Skelbimo kalba setting_default_privacy: Skelbimo privatumas setting_default_sensitive: Visada žymėti mediją kaip jautrią setting_delete_modal: Rodyti patvirtinimo dialogą prieš ištrinant įrašą + setting_disable_swiping: Išjungti perbraukimo judėjimus setting_display_media: Medijos rodymas setting_display_media_hide_all: Slėpti viską setting_display_media_show_all: Rodyti viską setting_expand_spoilers: Visada išplėsti įrašus, pažymėtus turinio įspėjimais setting_hide_network: Slėpti savo socialinę diagramą + setting_reduce_motion: Sumažinti judėjimą animacijose setting_system_font_ui: Naudoti numatytąjį sistemos šriftą setting_theme: Svetainės tema + setting_trends: Rodyti šiandienos trendus + setting_use_blurhash: Rodyti spalvingus paslėptos medijos gradientus setting_use_pending_items: Lėtas režimas title: Pavadinimas type: Importo tipas @@ -175,6 +185,7 @@ lt: hint: Papildoma informacija text: Taisyklė settings: + indexable: Įtraukti profilio puslapį į paieškos variklius show_application: Rodyti, iš kurios programėles išsiuntei įrašą tag: listable: Leisti šį saitažodį rodyti paieškose ir pasiūlymuose diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml index 3b10053196..8bc717fe1f 100644 --- a/config/locales/simple_form.nl.yml +++ b/config/locales/simple_form.nl.yml @@ -77,11 +77,13 @@ nl: warn: Verberg de gefilterde inhoud achter een waarschuwing, met de titel van het filter als waarschuwingstekst form_admin_settings: activity_api_enabled: Aantallen lokaal gepubliceerde berichten, actieve gebruikers en nieuwe registraties per week + app_icon: WEBP, PNG, GIF of JPG. Vervangt op mobiele apparaten het standaard app-pictogram met een aangepast pictogram. backups_retention_period: Gebruikers hebben de mogelijkheid om archieven van hun berichten te genereren om later te downloaden. Indien ingesteld op een positieve waarde, worden deze archieven automatisch verwijderd uit jouw opslag na het opgegeven aantal dagen. bootstrap_timeline_accounts: Deze accounts worden bovenaan de aanbevelingen aan nieuwe gebruikers getoond. Meerdere gebruikersnamen met komma's scheiden. closed_registrations_message: Weergegeven wanneer registratie van nieuwe accounts is uitgeschakeld content_cache_retention_period: Alle berichten van andere servers (inclusief boosts en reacties) worden verwijderd na het opgegeven aantal dagen, ongeacht enige lokale gebruikersinteractie met die berichten. Dit betreft ook berichten die een lokale gebruiker aan diens bladwijzers heeft toegevoegd of als favoriet heeft gemarkeerd. Privéberichten tussen gebruikers van verschillende servers gaan ook verloren en zijn onmogelijk te herstellen. Het gebruik van deze instelling is bedoeld voor servers die een speciaal doel dienen en overtreedt veel gebruikersverwachtingen wanneer deze voor algemeen gebruik wordt geïmplementeerd. custom_css: Je kunt aangepaste CSS toepassen op de webversie van deze Mastodon-server. + favicon: WEBP, PNG, GIF of JPG. Vervangt de standaard Mastodon favicon met een aangepast pictogram. mascot: Overschrijft de illustratie in de geavanceerde webomgeving. media_cache_retention_period: Mediabestanden van berichten van externe gebruikers worden op jouw server in de cache opgeslagen. Indien ingesteld op een positieve waarde, worden media verwijderd na het opgegeven aantal dagen. Als de mediagegevens worden opgevraagd nadat ze zijn verwijderd, worden ze opnieuw gedownload wanneer de originele inhoud nog steeds beschikbaar is. Vanwege beperkingen op hoe vaak linkvoorbeelden sites van derden raadplegen, wordt aanbevolen om deze waarde in te stellen op ten minste 14 dagen. Anders worden linkvoorbeelden niet op aanvraag bijgewerkt. peers_api_enabled: Een lijst met domeinnamen die deze server heeft aangetroffen in de fediverse. Er zijn hier geen gegevens inbegrepen over de vraag of je verbonden bent met een bepaalde server, alleen dat je server er van weet. Dit wordt gebruikt door diensten die statistieken over de federatie in algemene zin verzamelen. diff --git a/config/locales/simple_form.nn.yml b/config/locales/simple_form.nn.yml index 51dce245d2..bdd3db040d 100644 --- a/config/locales/simple_form.nn.yml +++ b/config/locales/simple_form.nn.yml @@ -77,6 +77,7 @@ nn: warn: Skjul det filtrerte innhaldet bak ei åtvaring som nemner tittelen på filteret form_admin_settings: activity_api_enabled: Tal på lokale innlegg, aktive brukarar og nyregistreringar kvar veke + app_icon: WEBP, PNG, GIF eller JPG. Overstyrer standard-ikonet på mobile einingar med eit tilpassa ikon. backups_retention_period: Brukarar har moglegheit til å generere arkiv av sine innlegg for å laste ned seinare. Når sett til ein positiv verdi, blir desse arkiva automatisk sletta frå lagringa etter eit gitt antal dagar. bootstrap_timeline_accounts: Desse kontoane vil bli festa øverst på fylgjaranbefalingane til nye brukarar. closed_registrations_message: Vist når det er stengt for registrering diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml index 5c0c640287..9d82384af9 100644 --- a/config/locales/simple_form.pl.yml +++ b/config/locales/simple_form.pl.yml @@ -77,11 +77,13 @@ pl: warn: Ukryj filtrowaną zawartość za ostrzeżeniem wskazującym tytuł filtra form_admin_settings: activity_api_enabled: Liczby opublikowanych lokalnych postów, aktywnych użytkowników i nowych rejestracji w tygodniowych przedziałach + app_icon: WEBP, PNG, GIF, albo JPEG. Nadpisuje domyślną ikonę aplikacji na urządzeniach mobilnych. backups_retention_period: Użytkownicy mogą generować archiwa wpisów do późniejszego pobrania. Jeżeli ta wartość jest dodatnia, te archiwa zostaną automatycznie usunięte z twojego serwera po danej liczbie dni. bootstrap_timeline_accounts: Te konta zostaną przypięte na górze rekomendacji obserwacji nowych użytkowników. closed_registrations_message: Wyświetlane po zamknięciu rejestracji content_cache_retention_period: Wszystkie wpisy z innych serwerów (w tym podbicia i odpowiedzi) zostaną usunięte po danej liczbie dni, bez względu na interakcje z nimi twoich użytkowników. Zawierają się w tym wpisy, które twoi użytkownicy dodali do zakładek lub ulubionych. Prywatne wzmianki od innych instancji zostaną utracone i będą nieprzywracalne. To ustawienie jest przeznaczone dla instancji zastosowania specjalnego i jest niezgodne z wieloma oczekiwaniami użytkowników. custom_css: Możesz zastosować niestandardowe style w internetowej wersji Mastodon. + favicon: WEBP, PNG, GIF, albo JPEG. Nadpisuje domyślną faviconę Mastodona. mascot: Nadpisuje ilustrację w zaawansowanym interfejsie internetowym. media_cache_retention_period: Media z wpisów od obcych użytkowników są cache'owane na twoim serwerze. Kiedy dana wartość jest dodatnia, media te będą usunięte po tylu dniach. Jeżeli usunięte media zostaną potem zażądane, oryginał zostanie ponownie pobrany (o ile jest dalej dostępny). Z powodu ograniczeń dot. częstotliwości z jaką karty podglądu linków dopytują się o dane od stron trzecich, zalecana wartość to min. 14 dni, bo karty podglądu linków nie będą wcześniej odświeżane na żądane. peers_api_enabled: Lista nazw domen, z którymi ten serwer spotkał się w fediverse. Nie są tu zawarte żadne dane o tym, czy użytkownik dokonuje federacji z danym serwerem, a jedynie, że jego serwer o tym wie. Jest to wykorzystywane przez serwisy, które zbierają statystyki dotyczące federacji w ogólnym sensie. diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml index a26468894b..7fcbb210c5 100644 --- a/config/locales/simple_form.pt-PT.yml +++ b/config/locales/simple_form.pt-PT.yml @@ -77,11 +77,13 @@ pt-PT: warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro form_admin_settings: activity_api_enabled: Contagem, em blocos semanais, de publicações locais, utilizadores ativos e novos registos + app_icon: WEBP, PNG, GIF ou JPG. Substitui o ícone padrão do aplicativo em dispositivos móveis por um ícone personalizado. backups_retention_period: Os utilizadores têm a possibilidade de gerar arquivos das suas mensagens para descarregar mais tarde. Quando definido para um valor positivo, estes arquivos serão automaticamente eliminados do seu armazenamento após o número de dias especificado. bootstrap_timeline_accounts: Estas contas serão destacadas no topo das recomendações aos novos utilizadores. closed_registrations_message: Apresentado quando as inscrições estiverem encerradas content_cache_retention_period: Todas as publicações de outros servidores (incluindo boosts e respostas) serão eliminadas após o número de dias especificado, independentemente de qualquer interação do utilizador local com essas publicações. Isto inclui publicações em que um utilizador local as tenha marcado como favoritas ou adicionado aos items salvos. As menções privadas entre utilizadores de instâncias diferentes também se perderão e serão impossíveis de restaurar. A utilização desta definição destina-se a instâncias para fins especiais e quebra muitas expectativas dos utilizadores quando implementada para utilização geral. custom_css: Pode aplicar estilos personalizados na versão web do Mastodon. + favicon: WEBP, PNG, GIF ou JPG. Substitui o ícone de favorito padrão do Mastodon por um ícone personalizado. mascot: Sobrepõe-se à ilustração na interface web avançada. media_cache_retention_period: Os ficheiros multimédia de publicações feitas por utilizadores remotos são armazenados em cache no seu servidor. Quando definido para um valor positivo, os ficheiros multimédia serão eliminados após o número de dias especificado. Se os ficheiros multimédia forem solicitados depois de terem sido eliminados, serão transferidos novamente, se o conteúdo de origem ainda estiver disponível. Devido a restrições sobre a frequência com que os cartões de pré-visualização de links pesquisam sites de terceiros, recomenda-se que este valor seja definido para, pelo menos, 14 dias, ou os cartões de pré-visualização de links não serão atualizados a pedido antes desse período. peers_api_enabled: Uma lista de nomes de domínio que este servidor encontrou no fediverso. Nenhum dado é incluído aqui sobre se você federa com um determinado servidor, apenas que o seu servidor o conhece. Este serviço é utilizado por serviços que recolhem estatísticas na federação, em termos gerais. diff --git a/config/locales/simple_form.sr-Latn.yml b/config/locales/simple_form.sr-Latn.yml index 6bee31a42c..8dd1986563 100644 --- a/config/locales/simple_form.sr-Latn.yml +++ b/config/locales/simple_form.sr-Latn.yml @@ -77,11 +77,13 @@ sr-Latn: warn: Sakrij filtrirani sadržaj iza upozorenja u kome se navodi naziv filtera form_admin_settings: activity_api_enabled: Brojevi lokalno postavljenih objava, aktivnih korisnika i novih registracija na nedeljnoj bazi + app_icon: WEBP, PNG, GIF ili JPG. Zamenjuje podrazumevanu ikonicu aplikacije na mobilnim uređajima prilagođenom ikonicom. backups_retention_period: Korisnici imaju mogućnost da generišu arhive svojih objava za kasnije preuzimanje. Kada se podese na pozitivnu vrednost, ove arhive će se automatski izbrisati iz vašeg skladišta nakon navedenog broja dana. bootstrap_timeline_accounts: Ovi nalozi će biti zakačeni na vrh preporuka za praćenje novih korisnika. closed_registrations_message: Prikazuje se kada su registracije zatvorene content_cache_retention_period: Sve objave sa drugih servera (uključujući podržavanja i odgovore) će biti izbrisane nakon navedenog broja dana, bez obzira na bilo kakvu interakciju lokalnog korisnika sa tim objavama. Ovo uključuje objave u kojima ih je lokalni korisnik označio kao obeleživače ili omiljene. Privatna pominjanja između korisnika sa različitih instanci će takođe biti izgubljena i nemoguće ih je vratiti. Korišćenje ove postavke je namenjeno za slučajeve posebne namene i krši mnoga očekivanja korisnika kada se primeni za upotrebu opšte namene. custom_css: Možete da primenite prilagođene stilove na veb verziji Mastodon-a. + favicon: WEBP, PNG, GIF ili JPG. Zamenjuje podrazumevani Mastodon favikon prilagođenom ikonicom. mascot: Zamenjuje ilustraciju u naprednom veb okruženju. media_cache_retention_period: Medijske datoteke iz objava udaljenih korisnika se keširaju na vašem serveru. Kada se podesi na pozitivnu vrednost, mediji će biti izbrisani nakon navedenog broja dana. Ako se medijski podaci zahtevaju nakon brisanja, biće ponovo preuzeti, ako je izvorni sadržaj i dalje dostupan. Zbog ograničenja koliko često kartice za pregled veza anketiraju sajtove trećih strana, preporučuje se da ovu vrednost postavite na najmanje 14 dana, inače kartice za pregled veza neće biti ažurirane na zahtev pre tog vremena. peers_api_enabled: Lista domena sa kojima se ovaj server susreo u fediverzumu. Ovde nisu sadržani podaci o tome da li se Vaš server federiše sa drugim serverima, već samo da Vaš server zna za njih. Ove informacije koriste servisi koji prikupljaju podatke i vode statistiku o federaciji u širem smislu. diff --git a/config/locales/simple_form.sr.yml b/config/locales/simple_form.sr.yml index 4ec8374075..e88a99df13 100644 --- a/config/locales/simple_form.sr.yml +++ b/config/locales/simple_form.sr.yml @@ -77,11 +77,13 @@ sr: warn: Сакриј филтрирани садржај иза упозорења у коме се наводи назив филтера form_admin_settings: activity_api_enabled: Бројеви локално постављених објава, активних корисника и нових регистрација на недељној бази + app_icon: WEBP, PNG, GIF или JPG. Замењује подразумевану иконицу апликације на мобилним уређајима прилагођеном иконицом. backups_retention_period: Корисници имају могућност да генеришу архиве својих објава за касније преузимање. Када се подесе на позитивну вредност, ове архиве ће се аутоматски избрисати из вашег складишта након наведеног броја дана. bootstrap_timeline_accounts: Ови налози ће бити закачени на врх препорука за праћење нових корисника. closed_registrations_message: Приказује се када су регистрације затворене content_cache_retention_period: Све објаве са других сервера (укључујући подржавања и одговоре) ће бити избрисане након наведеног броја дана, без обзира на било какву интеракцију локалног корисника са тим објавама. Ово укључује објаве у којима их је локални корисник означио као обележиваче или омиљене. Приватна помињања између корисника са различитих инстанци ће такође бити изгубљена и немогуће их је вратити. Коришћење ове поставке је намењено за случајеве посебне намене и крши многа очекивања корисника када се примени за употребу опште намене. custom_css: Можете да примените прилагођене стилове на веб верзији Mastodon-а. + favicon: WEBP, PNG, GIF или JPG. Замењује подразумевани Mastodon фавикон прилагођеном иконицом. mascot: Замењује илустрацију у напредном веб окружењу. media_cache_retention_period: Медијске датотеке из објава удаљених корисника се кеширају на вашем серверу. Када се подеси на позитивну вредност, медији ће бити избрисани након наведеног броја дана. Ако се медијски подаци захтевају након брисања, биће поново преузети, ако је изворни садржај и даље доступан. Због ограничења колико често картице за преглед веза анкетирају сајтове трећих страна, препоручује се да ову вредност поставите на најмање 14 дана, иначе картице за преглед веза неће бити ажуриране на захтев пре тог времена. peers_api_enabled: Листа домена са којима се овај сервер сусрео у федиверзуму. Овде нису садржани подаци о томе да ли се Ваш сервер федерише са другим серверима, већ само да Ваш сервер зна за њих. Ове информације користе сервиси који прикупљају податке и воде статистику о федерацији у ширем смислу. diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml index e68642c2f6..0816efcc5f 100644 --- a/config/locales/simple_form.th.yml +++ b/config/locales/simple_form.th.yml @@ -77,12 +77,15 @@ th: warn: ซ่อนเนื้อหาที่กรองอยู่หลังคำเตือนที่กล่าวถึงชื่อเรื่องของตัวกรอง form_admin_settings: activity_api_enabled: จำนวนโพสต์ที่เผยแพร่ในเซิร์ฟเวอร์, ผู้ใช้ที่ใช้งานอยู่ และการลงทะเบียนใหม่ในบักเก็ตรายสัปดาห์ + app_icon: WEBP, PNG, GIF หรือ JPG เขียนทับไอคอนแอปเริ่มต้นในอุปกรณ์มือถือด้วยไอคอนที่กำหนดเอง backups_retention_period: ผู้ใช้มีความสามารถในการสร้างการเก็บถาวรของโพสต์ของเขาเพื่อดาวน์โหลดในภายหลัง เมื่อตั้งเป็นค่าบวก จะลบการเก็บถาวรเหล่านี้ออกจากที่เก็บข้อมูลของคุณโดยอัตโนมัติหลังจากจำนวนวันที่ระบุ bootstrap_timeline_accounts: จะปักหมุดบัญชีเหล่านี้ไว้ด้านบนสุดของคำแนะนำการติดตามของผู้ใช้ใหม่ closed_registrations_message: แสดงเมื่อมีการปิดการลงทะเบียน content_cache_retention_period: จะลบโพสต์ทั้งหมดจากเซิร์ฟเวอร์อื่น ๆ (รวมถึงการดันและการตอบกลับ) หลังจากจำนวนวันที่ระบุ โดยไม่คำนึงถึงการโต้ตอบใด ๆ ของผู้ใช้ในเซิร์ฟเวอร์กับโพสต์เหล่านั้น สิ่งนี้รวมถึงโพสต์ที่ผู้ใช้ในเซิร์ฟเวอร์ได้ทำเครื่องหมายโพสต์ว่าเป็นที่คั่นหน้าหรือรายการโปรด การกล่าวถึงแบบส่วนตัวระหว่างผู้ใช้จากอินสแตนซ์ที่แตกต่างกันจะหายไปและไม่สามารถคืนค่าได้เช่นกัน การใช้การตั้งค่านี้มีไว้สำหรับอินสแตนซ์ที่มีวัตถุประสงค์พิเศษและทำลายความคาดหวังของผู้ใช้จำนวนมากเมื่อนำไปใช้สำหรับการใช้งานที่มีวัตถุประสงค์ทั่วไป custom_css: คุณสามารถนำไปใช้ลักษณะที่กำหนดเองใน Mastodon รุ่นเว็บ + favicon: WEBP, PNG, GIF หรือ JPG เขียนทับ Favicon ของ Mastodon เริ่มต้นด้วยไอคอนที่กำหนดเอง mascot: เขียนทับภาพประกอบในส่วนติดต่อเว็บขั้นสูง + media_cache_retention_period: จะแคชไฟล์สื่อจากโพสต์ที่สร้างโดยผู้ใช้ระยะไกลในเซิร์ฟเวอร์ของคุณ เมื่อตั้งเป็นค่าบวก จะลบสื่อหลังจากจำนวนวันที่ระบุ หากมีการขอข้อมูลสื่อหลังจากมีการลบสื่อ จะดาวน์โหลดสื่อใหม่ หากเนื้อหาต้นฉบับยังคงใช้งานได้ เนื่องจากข้อจำกัดเกี่ยวกับความถี่ที่บัตรตัวอย่างลิงก์สำรวจไซต์จากบุคคลที่สาม ขอแนะนำให้ตั้งค่านี้เป็นอย่างน้อย 14 วัน มิฉะนั้นจะไม่อัปเดตบัตรตัวอย่างลิงก์ตามความต้องการก่อนเวลานั้น peers_api_enabled: รายการชื่อโดเมนที่เซิร์ฟเวอร์นี้พบในจักรวาลสหพันธ์ ไม่มีข้อมูลรวมอยู่ที่นี่เกี่ยวกับว่าคุณติดต่อกับเซิร์ฟเวอร์ที่กำหนดหรือไม่ เพียงแค่ว่าเซิร์ฟเวอร์ของคุณทราบเกี่ยวกับเซิร์ฟเวอร์ที่กำหนด มีการใช้สิ่งนี้โดยบริการที่เก็บรวบรวมสถิติในการติดต่อกับภายนอกในความหมายทั่วไป profile_directory: ไดเรกทอรีโปรไฟล์แสดงรายการผู้ใช้ทั้งหมดที่ได้เลือกรับให้สามารถค้นพบได้ require_invite_text: เมื่อการลงทะเบียนต้องการการอนุมัติด้วยตนเอง ทำให้การป้อนข้อความ “ทำไมคุณจึงต้องการเข้าร่วม?” บังคับแทนที่จะไม่จำเป็น diff --git a/config/locales/simple_form.tr.yml b/config/locales/simple_form.tr.yml index 4ec35f1024..697417a541 100644 --- a/config/locales/simple_form.tr.yml +++ b/config/locales/simple_form.tr.yml @@ -77,11 +77,13 @@ tr: warn: Süzgeçlenmiş içeriği, süzgecinin başlığından söz eden bir uyarının arkasında gizle form_admin_settings: activity_api_enabled: Yerel olarak yayınlanan gönderi, etkin kullanıcı ve yeni kayıtların haftalık sayıları + app_icon: WEBP, PNG, GIF veya JPG. Mobil aygıtlarda varsayılan uygulama simgesini isteğe bağlı bir simgeyle değiştirir. backups_retention_period: Kullanıcılar, gönderilerinin arşivlerini daha sonra indirmek üzere oluşturabilirler. Pozitif bir değer verdilğinde bu arşivler verilmiş olan gün sonunda deponuzdan otomatik olarak silinecektir. bootstrap_timeline_accounts: Bu hesaplar, yeni kullanıcıların takip önerilerinin tepesinde sabitlenecektir. closed_registrations_message: Kayıt olma kapalıyken görüntülenir content_cache_retention_period: Diğer sunuculardaki (öne çıkarma ve yanıtlar da dahil olmak üzere) tüm gönderiler belirlenen gün sonunda, yerel bir kullanıcının etkileşimine bakılmadan, silinecektir. Yerel bir kullanıcının yerimlerine veya favorilerine eklediği gönderiler de dahildir. Farklı sunuculardaki kullanıcılar arasındaki özel bahsetmeler de kaybolacak ve geri getirilmeleri mümkün olmayacaktır. Bu ayarın kullanımı özel amaçlı sunucular içindir ve genel amaçlı kullanımda etkinleştirildiğinde kullanıcı beklentilerini karşılamayabilir. custom_css: Mastodon'un web sürümüne özel biçimler uygulayabilirsiniz. + favicon: WEBP, PNG, GIF veya JPG. Varsayılan Mastodon simgesini isteğe bağlı bir simgeyle değiştirir. mascot: Gelişmiş web arayüzündeki illüstrasyonu geçersiz kılar. media_cache_retention_period: Uzak kullanıcıların gönderilerindeki ortam dosyaları sunucunuzda önbelleklenir. Pozitif bir değer verildiğinde, ortam dosyaları belirlenen gün sonunda silinecektir. Eğer ortam dosyaları silindikten sonra istenirse, kaynak içerik hala mevcutsa, tekrar indirilecektir. Bağlantı önizleme kartlarının üçüncü parti siteleri yoklamasına ilişkin kısıtlamalar nedeniyle, bu değeri en azından 14 gün olarak ayarlamanız önerilir, yoksa bağlantı önizleme kartları bu süreden önce isteğe bağlı olarak güncellenmeyecektir. peers_api_enabled: Bu sunucunun fediverse'te karşılaştığı alan adlarının bir listesi. İlgili sunucuyla birleştirme mi yapıyorsunuz yoksa sunucunuz sadece onu biliyor mu hakkında bir bilgi burada yok. Bu blgi genel olarak federasyın hakkında istatistik toplamak isteyen hizmetler tarafından kullanılıyor. diff --git a/config/locales/simple_form.vi.yml b/config/locales/simple_form.vi.yml index bc9a181ed3..e5063e6112 100644 --- a/config/locales/simple_form.vi.yml +++ b/config/locales/simple_form.vi.yml @@ -77,11 +77,13 @@ vi: warn: Ẩn nội dung đã lọc đằng sau một cảnh báo đề cập đến tiêu đề của bộ lọc form_admin_settings: activity_api_enabled: Số lượng tút được đăng trong máy chủ, người dùng đang hoạt động và đăng ký mới hàng tuần + app_icon: WEBP, PNG, GIF hoặc JPG. Dùng biểu tượng tùy chỉnh trên thiết bị di động. backups_retention_period: Người dùng có khả năng tạo bản sao lưu các tút của họ để tải xuống sau. Các bản sao lưu này sẽ tự động bị xóa khỏi bộ nhớ của bạn sau số ngày được chỉ định. bootstrap_timeline_accounts: Những người này sẽ được ghim vào đầu các gợi ý theo dõi của người mới. closed_registrations_message: Được hiển thị khi đóng đăng ký content_cache_retention_period: Tất cả tút từ các máy chủ khác (bao gồm cả đăng lại và trả lời) sẽ bị xóa sau số ngày được chỉ định mà không tính đến bất kỳ tương tác nào của người dùng cục bộ với các tút đó. Điều này bao gồm các tút mà người dùng cục bộ đã đánh dấu nó là dấu trang hoặc mục yêu thích. Những lượt nhắc riêng tư giữa những người dùng từ các máy chủ khác nhau cũng sẽ bị mất và không thể khôi phục. Việc sử dụng cài đặt này dành cho các trường hợp có mục đích đặc biệt và phá vỡ nhiều kỳ vọng của người dùng khi được triển khai cho mục đích sử dụng chung. custom_css: Bạn có thể tùy chỉnh phong cách trên bản web của Mastodon. + favicon: WEBP, PNG, GIF hoặc JPG. Dùng favicon Maston tùy chỉnh. mascot: Ghi đè hình minh họa trong giao diện web nâng cao. media_cache_retention_period: Các tệp phương tiện từ các tút do người dùng máy chủ khác thực hiện sẽ được lưu vào bộ đệm trên máy chủ của bạn. Khi được đặt thành giá trị dương, phương tiện sẽ bị xóa sau số ngày được chỉ định. Nếu dữ liệu phương tiện được yêu cầu sau khi bị xóa, dữ liệu đó sẽ được tải xuống lại nếu nội dung nguồn vẫn còn. Do những hạn chế về tần suất thẻ xem trước liên kết thăm dò ý kiến ​​các trang web của bên thứ ba, bạn nên đặt giá trị này thành ít nhất 14 ngày, nếu không thẻ xem trước liên kết sẽ không được cập nhật theo yêu cầu trước thời gian đó. peers_api_enabled: Danh sách các máy chủ khác mà máy chủ này đã liên hợp. Không có dữ liệu nào được đưa vào đây về việc bạn có liên kết với một máy chủ nhất định hay không, chỉ là máy chủ của bạn biết về nó. Điều này được sử dụng bởi các dịch vụ thu thập số liệu thống kê về liên kết theo nghĩa chung. diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml index a06a5ab4e4..6058cc00cf 100644 --- a/config/locales/simple_form.zh-CN.yml +++ b/config/locales/simple_form.zh-CN.yml @@ -77,11 +77,13 @@ zh-CN: warn: 在警告中提及过滤器标题后,隐藏过滤内容 form_admin_settings: activity_api_enabled: 本站每周的嘟文数、活跃用户数和新注册用户数 + app_icon: WEBP、PNG、GIF 或 JPG。使用自定义图标覆盖移动设备上的默认应用图标。 backups_retention_period: 用户可以生成其嘟文存档以供之后下载。当该值被设为正值时,这些存档将在指定的天数后自动从您的存储中删除。 bootstrap_timeline_accounts: 这些账号将在新用户关注推荐中置顶。 closed_registrations_message: 在关闭注册时显示 content_cache_retention_period: 来自其它实例的所有嘟文(包括转嘟与回复)都将在指定天数后被删除,不论本实例用户是否与这些嘟文产生过交互。这包括被本实例用户喜欢和收藏的嘟文。实例间用户的私下提及也将丢失并无法恢复。此设置针对的是特殊用途的实例,用于一般用途时会打破许多用户的期望。 custom_css: 你可以为网页版 Mastodon 应用自定义样式。 + favicon: WEBP、PNG、GIF 或 JPG。使用自定义图标覆盖 Mastodon 的默认图标。 mascot: 覆盖高级网页界面中的绘图形象。 media_cache_retention_period: 来自外站用户嘟文的媒体文件将被缓存到你的实例上。当该值被设为正值时,缓存的媒体文件将在指定天数后被清除。如果媒体文件在被清除后重新被请求,且源站内容仍然可用,它将被重新下载。由于链接预览卡拉取第三方站点的频率受到限制,建议将此值设置为至少 14 天,如果小于该值,链接预览卡将不会按需更新。 peers_api_enabled: 此服务器在联邦宇宙中遇到的域名列表。 这里不包含关于您是否与给定服务器联合的数据,只是您的服务器知道它。 这由收集一般意义上的联邦统计信息的服务使用。 diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml index a9e5921be0..b7a67c6a6f 100644 --- a/config/locales/simple_form.zh-TW.yml +++ b/config/locales/simple_form.zh-TW.yml @@ -77,11 +77,13 @@ zh-TW: warn: 隱藏過濾內容於過濾器標題之警告後 form_admin_settings: activity_api_enabled: 本站使用者的嘟文數量,以及本站的活躍使用者與一週內新使用者數量 + app_icon: WEBP、PNG、GIF、或 JPG。於行動裝置上使用自訂圖示替代預設應用程式圖示。 backups_retention_period: 使用者能產生他們嘟文的備份以便日後下載。當設定為正值時,這些嘟文備份將於指定之天數後自您的儲存空間中自動刪除。 bootstrap_timeline_accounts: 這些帳號將被釘選於新帳號跟隨推薦之上。 closed_registrations_message: 於註冊關閉時顯示 content_cache_retention_period: 所有來自其他伺服器之嘟文(包括轉嘟與回嘟)將於指定之天數後自動刪除,不論這些嘟文與本地使用者間的任何互動。這將包含本地使用者已標記為書籤或最愛之嘟文。不同站點使用者間之私訊亦將遺失且不可回復。此設定應適用於特殊情況,若常規使用將超乎多數使用者預期。 custom_css: 您於 Mastodon 網頁版本中能套用客製化風格。 + favicon: WEBP、PNG、GIF、或 JPG。使用自訂圖示替代預設 Mastodon favicon 圖示。 mascot: 覆寫進階網頁介面中的圖例。 media_cache_retention_period: 來自遠端伺服器嘟文中之多媒體內容將快取於您的伺服器。當設定為正值時,這些多媒體內容將於指定之天數後自您的儲存空間中自動刪除。若多媒體資料於刪除後被請求,且原始內容仍可存取,它們將被重新下載。由於連結預覽中第三方網站查詢頻率限制,建議將其設定為至少 14 日,否則於此之前連結預覽將不被即時更新。 peers_api_enabled: 浩瀚聯邦宇宙中與此伺服器曾經擦肩而過的網域列表。不包含關於您是否與此伺服器是否有與之串連,僅僅表示您的伺服器已知此網域。這是供收集聯邦宇宙中一般性統計資料服務使用。 From 8540004f7b473df47e49d8dc5397ff590245553a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 09:39:04 +0000 Subject: [PATCH 108/658] Update dependency dotenv to v3.1.2 (#30197) 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 190888ddb8..23c29cabd2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -217,7 +217,7 @@ GEM domain_name (0.6.20240107) doorkeeper (5.6.9) railties (>= 5) - dotenv (3.1.1) + dotenv (3.1.2) drb (2.2.1) ed25519 (1.3.0) elasticsearch (7.17.10) From 5cd13ee4f19c112ea855063c2495e2874746f23a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 11:39:20 +0200 Subject: [PATCH 109/658] Update dependency aws-sdk-s3 to v1.149.1 (#30196) 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 23c29cabd2..435144700f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -101,7 +101,7 @@ GEM awrence (1.2.1) aws-eventstream (1.3.0) aws-partitions (1.922.0) - aws-sdk-core (3.194.0) + aws-sdk-core (3.194.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) @@ -109,7 +109,7 @@ GEM aws-sdk-kms (1.80.0) aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.149.0) + aws-sdk-s3 (1.149.1) aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) From c9ccba7045f1127be0d89bf941b9ba381e2cb722 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 May 2024 14:43:11 +0200 Subject: [PATCH 110/658] Update dependency sass to v1.77.0 (#30200) 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 399dae2057..95a3923e25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15320,15 +15320,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.76.0 - resolution: "sass@npm:1.76.0" + version: 1.77.0 + resolution: "sass@npm:1.77.0" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/976baf2c378e104f8d4ffca5375c8aa6f3d24f59d5c0a5db8d68a51f89edce45dedc25cfcd304b309fc8568d146de9e2c6cd189395e97bb2840d39feb13932ff + checksum: 10c0/bce0e5f5b535491e4e775045a79f19cbe10d800ef53b5f7698958d2992505d7b124c968169b05a0190842d8e0a24c2aa6d75dfbdd7c213820d9d59e227009c19 languageName: node linkType: hard From d8c428472356abd70aaf1f514b99114464ee7f61 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 7 May 2024 20:15:17 +0200 Subject: [PATCH 111/658] Ensure custom favicon is converted to PNG and ICO (#30208) --- app/models/site_upload.rb | 19 +++++++++++++++++-- app/views/layouts/application.html.haml | 2 +- config/imagemagick/policy.xml | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/models/site_upload.rb b/app/models/site_upload.rb index b3926ec7ed..6431d1007d 100644 --- a/app/models/site_upload.rb +++ b/app/models/site_upload.rb @@ -26,8 +26,23 @@ class SiteUpload < ApplicationRecord APP_ICON_SIZES = (APPLE_ICON_SIZES + ANDROID_ICON_SIZES).uniq.freeze STYLES = { - app_icon: APP_ICON_SIZES.each_with_object({}) { |size, hash| hash[size.to_s.to_sym] = "#{size}x#{size}#" }.freeze, - favicon: FAVICON_SIZES.each_with_object({}) { |size, hash| hash[size.to_s.to_sym] = "#{size}x#{size}#" }.freeze, + app_icon: + APP_ICON_SIZES.to_h do |size| + [:"#{size}", { format: 'png', geometry: "#{size}x#{size}#", file_geometry_parser: FastGeometryParser }] + end.freeze, + + favicon: { + ico: { + format: 'ico', + geometry: '48x48#', + file_geometry_parser: FastGeometryParser, + }.freeze, + }.merge( + FAVICON_SIZES.to_h do |size| + [:"#{size}", { format: 'png', geometry: "#{size}x#{size}#", file_geometry_parser: FastGeometryParser }] + end + ).freeze, + thumbnail: { '@1x': { format: 'png', diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 56857b2b63..e3d05226ee 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -11,7 +11,7 @@ - if storage_host? %link{ rel: 'dns-prefetch', href: storage_host }/ - %link{ rel: 'icon', href: site_icon_path('favicon') || '/favicon.ico', type: 'image/x-icon' }/ + %link{ rel: 'icon', href: site_icon_path('favicon', 'ico') || '/favicon.ico', type: 'image/x-icon' }/ - SiteUpload::FAVICON_SIZES.each do |size| %link{ rel: 'icon', sizes: "#{size}x#{size}", href: site_icon_path('favicon', size.to_i) || frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/ diff --git a/config/imagemagick/policy.xml b/config/imagemagick/policy.xml index e2aa202f27..2730a9f84e 100644 --- a/config/imagemagick/policy.xml +++ b/config/imagemagick/policy.xml @@ -23,5 +23,5 @@ - + From ac041ceefa52bba4ec9a11daf93323d2c3d5d78d Mon Sep 17 00:00:00 2001 From: Essem Date: Wed, 8 May 2024 14:12:58 -0500 Subject: [PATCH 112/658] Remove custom favicon/app icons Upstream now includes a way to change them from the admin UI. --- README.md | 3 +-- .../icons/android-chrome-144x144.png | Bin 28721 -> 5810 bytes .../icons/android-chrome-192x192.png | Bin 45705 -> 8741 bytes .../icons/android-chrome-256x256.png | Bin 76264 -> 11993 bytes app/javascript/icons/android-chrome-36x36.png | Bin 5686 -> 950 bytes .../icons/android-chrome-384x384.png | Bin 165191 -> 21112 bytes app/javascript/icons/android-chrome-48x48.png | Bin 7225 -> 1384 bytes .../icons/android-chrome-512x512.png | Bin 309782 -> 31858 bytes app/javascript/icons/android-chrome-72x72.png | Bin 11116 -> 2262 bytes app/javascript/icons/android-chrome-96x96.png | Bin 15966 -> 3306 bytes app/javascript/icons/favicon-16x16.png | Bin 3890 -> 588 bytes app/javascript/icons/favicon-32x32.png | Bin 5192 -> 1114 bytes app/javascript/icons/favicon-48x48.png | Bin 7225 -> 1680 bytes public/chuckya.png | Bin 0 -> 76264 bytes 14 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 public/chuckya.png diff --git a/README.md b/README.md index 12670f9325..ff51d6c3fb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Chuckya +# Chuckya Chuckya is a close-to-upstream soft fork of Mastodon Glitch Edition (more commonly known as glitch-soc) that aims to introduce more experimental features/fixes with the goal of making the overall experience more enjoyable. Although it's mainly developed for and used on the [wetdry.world](https://wetdry.world) instance, it can be deployed by any server admin as a drop-in, backwards-compatible replacement for Mastodon. @@ -15,7 +15,6 @@ Here are some of the changes compared to glitch-soc: - Allows dashes in custom emote names - Emojis can be put side-by-side - Minor media attachment tweaks -- Custom favicon Changes previously in Chuckya that made their way into vanilla Mastodon: diff --git a/app/javascript/icons/android-chrome-144x144.png b/app/javascript/icons/android-chrome-144x144.png index eb550caf810c132bfc03623c427b1d2935e0223b..698fb4a260b13621d40468ad5f3fb3438568748d 100644 GIT binary patch literal 5810 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 literal 28721 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 diff --git a/app/javascript/icons/android-chrome-192x192.png b/app/javascript/icons/android-chrome-192x192.png index 44960b7bcddbf10baf5c603da9ef3db41d5c799c..2b6b632648f6b18918881287c8a8b295cbc81eb7 100644 GIT binary patch literal 8741 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 P00000NkvXXu0mjfxX8FH literal 45705 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 YJ|zFRT07`!5;Y{cT1Mz<4F|&i0q&mXLI3~& diff --git a/app/javascript/icons/android-chrome-256x256.png b/app/javascript/icons/android-chrome-256x256.png index eb6d3810e85b527dce41c993c1220d27698aabd5..51e3849a263062ccefb246dfcd2130114ee040ae 100644 GIT binary patch literal 11993 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≥QPq~fv_+VUfUxV%Lo{C#0gPKVas5#<8 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

m?@_?r}d5fYwCDe-i#z;8Y;(NmIdfpjzi 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 diff --git a/app/javascript/icons/android-chrome-512x512.png b/app/javascript/icons/android-chrome-512x512.png index 073250b3d06935cc0b15febb9a262e0960086eec..bffacfb699c6b1133f85269342adddcc0d185c14 100644 GIT binary patch literal 31858 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 literal 309782 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ĭ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�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 KAS+dE(EkT$6w!eI diff --git a/app/javascript/icons/android-chrome-72x72.png b/app/javascript/icons/android-chrome-72x72.png index 2f4711875bc70070015a7f2ac47ed4ddf9c5a4a3..16679d5731a6d62d7088d02b0590891f884ab737 100644 GIT binary patch delta 2261 zcmV;`2rBpNR@M=a8Gix*007#LBoF`q2%SkpK~#7F?V1H}8_D{_yT6%T$yPY$aB|G> zXZ}BCW@ct)W`0GFncp!pGc#kr5HzzbX?ObBakgB!m2>5)Q>fG>)_g1dwzt0#jDOd= zh5b<;`?4Bf4X_4S1FQko0F(AlFzsVt4ab0nV|g_)W=!K4<$p2+w~skiETo4V%GImc zvV@BltGR?yGmA|$14&Htuv`vF6+svq6M*qC4h(2;5IsF=YsJJV4YpTgY}Kmp?B}>+ zkMrIm6M;+uAnyqRLXxNuvrqtlxpSExKQgRaZq^l-htV7vcjSj#`$`dw?_}W|T zyrHeVb=5~dT|D?;dmNjO?9jt-$L)gZ=$KZlppPuS@9w@cnV_PX(fL9%%>htIlk#X# zdgb}8haPtD|3A(D_Loys&PPRaF-UT9Sap1~dwg|81_SiuJ4PWW9MDq3uAc7j@I9NN;ymXIAQvsN zw|~AXKIBlJ20ijn{MX-?2l~*par4Q)50mhP(!c!2+*iFmTDZ_v6J36B_2Tm?E-C_= z;J@e2^eIove_jJZfT=zi6BNSSdC04+H6hKM0|DTrubiavo*q2r*y#B$(rG7FX&#V| zOUr!o`^NYevokOH-XRuaISC;b2ks$a&SG^tG{?8rb3 zbOKNashN|4#9TF{pkRQxs44d}s#OW~%^0fHnV+3P%5!mwcj^R4HTM|+Qf3iy|jjsjq?QYoLYoy&6ysU|f`$1tmmjg1PsZpA`gU-;(yYE=rNF^Y(s za^-o)0HBVC;@C)9`?*~oilmPyi6rt|dV=zvt^ldN&0}m#yWq}l)NYIz1*h{_ePGzUt~&PgjDRe1xVF6##%XHI$f9vnWp!TyW+P2}(c!Sf`9(ps#0W zV9DJ1u4ZolKyo%vPf&ir8GnQAYdd}1oIS33I3`L2I=56auzYXGZp=nAmEUmX$XS2i zLeiOoRM#I&>0F^>L-o+3iZk>E0K_bnFRzU2%oF?1JGqtSqPPh#0g&qWV-D$C*H%$C z_4lSXT|IKe`9oVaZlif;kuib*sGh$B3t(tnJC0rI!ZQZ8Y)n=i7=KNimadHE%yq>k zBB%0rD37VTE9vP>yS7!kJJWR!kGHKGs8&V+nmOl-<~(hhs&0-6klNM__H-^;yu@P$ z8FA$WZCL>TMp4te179z;^r_;}je)l*|S7C0#b%}-I0IlJnSF+otZGJf6VLoa{h zLd>A!|E-CDz$|a7R)0skw~cmp3fo1I#%w?)h(@!>%!5XA5R}2!*D*;1&HN>2_dosl za~CYCZQ6=8@&7zy#ckL3K|8=gNCFZe0Hgq;_XWUm4Md~^Ioh1gO zj|-pr_Hr{KFX|nSxiAWMgRnuA%y8}N`C>!AAa>;azs&PFy3|R z=0E>5ddEjwkVhj6MSIVumQFN-J8v3kUtbyMOC%NwDl}Ph$<3Ybm#vIeu8Eefj&Htt z==@Xqr#Heqw`zc*a|MO*%g${b8%^H*iKTJT^8b=}U}CyE^vGfsv|8?GKT$~_xrbK` zNOJV>agvm;zkjS_OGoA1pImm}VTC+f{vYSOjFeKs0ouc01Ryy^a7t8O_wd$leZ2C2 z&z|?9*DYGIJgV_QX=Xig-`E{D4oM)icPu&Lb~cOPl_ZtX(cVkX?YZj0t;hZAqT~Lp zbj&|DuQ{|}#+pJ92*T12K&=3?d8s`)sf+TKm{oXoGidc7j2XDrf4%p?H>GNk=$>8zl}Ld?eU^afZ1 jtO3>lYk)Pt_7nXBJ)XA4jyl9|00000NkvXXu0mjfH?&-{ literal 11116 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 diff --git a/app/javascript/icons/android-chrome-96x96.png b/app/javascript/icons/android-chrome-96x96.png index dee0f6d69e3f62073a22fe7cdb3ed1bf934274bf..9ade87cf32c06bc58161a12b88b2e5b65d822957 100644 GIT binary patch literal 3306 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 diff --git a/app/javascript/icons/favicon-16x16.png b/app/javascript/icons/favicon-16x16.png index bdf2f913ee135c282e7df4234e6c180a830bb092..eed8e0035c34b51853e2f027f87171e682fecf7a 100644 GIT binary patch delta 574 zcmV-E0>S;V9?S%g8Gi-<001BJ|6u?C0uxC@K~#7FmCgffUQqxA;2X_b%tni~g=1~I zzs+d2?FF-K+qSLRw%ez^vwQ#c&OFJN_s%upv0CBha&@hCySrY}ZynV_p+_TCPko|x zyIdGfzKzo<2RQ9gGlhR*lVq1&auSxYW6|4T>8zr_OdKa*<9|8{^Jk0TW3y*;k4>2< zu+9lqYlk0k7~7NWrZzAO=5(N=Lj}*#Ln3x=6QK4Ci6XFaX(#x4o3Y(X?7EhzHhnXg zr;jDy;)8oTapXWJWEl_y6=zNe*uA|IiUNFmFN3eQ>zZZ|o2GuAOUdn%Tsf zQZ?3+QVE71zLf);Zl~aj1x!hq+Dg#qoAo&j9eXOGr<6V`!(*s0$ zz}I_+l_OFSp{s?KbfKqw5!1@%Uc*mw#?ZDjiCU(FMbeF$MTvhM0o0 zghdnbaey%@N2TzOnyIyxsJHzIk0CtkwIMtcoH624gdzM>q#-QRV2sH0>LW6Z^gq!Q zkvSwbHn%tVF}l!?$@;I~a5_SHsiZuSOPHOyLN0MLUGyJ|vl^yC~-v9sr M07*qoM6N<$g1?^~{r~^~ literal 3890 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 O1fbcu+160}Q~m+Sum_j` diff --git a/app/javascript/icons/favicon-32x32.png b/app/javascript/icons/favicon-32x32.png index 6c68991f5a4438c95cb5237e624bdf5c6a317c25..9165746bcfa5f7c94c013cc9ea9e355c675b454d 100644 GIT binary patch delta 1094 zcmV-M1iAajDB1{+BYy-TNkl$5`98ZQHhY z{H!<~ZZftf=Gn9Ad!woGsrsV-=Jp?lDKu&|?5)$mDxEI%xK5Y;0ojpHuTOX3`3MRk zKq)lxpLXO!Jg%$L>r?OR^>8EZb22m4x%z6@3lDmiR+}0@Fn@Q_4O%UnHtE4N8aP6y zNtm>n1k97DMw681J@_Ro9IjQx{0Qb*Qmcxt$bIz6=+_7q$N{t9nEa?-dho}H!(~V7=Mc(pndygMA!fyA>4gyK*;X9 zBari`Uwt7Yh$S46)Ks=H}Kx?j#3LA8FBq2L@I}<`aK9&NtBs1T! zH74Y^mSjXsD4-M#ClSy#Hj@HQJ^_>EK5uT`@CV8Lf0CS%CI!|F#t_gl3fSY2oj28y zm&oPF&3_wyC%GRBl1xB718e#x5YRR@MW_NX$j+Po2-5{}@`m5SQ~{DxCWHct)qVX4 zXd9>k4qFVe^Tyw)0(@>>|0~ITSb$`LAyQyfPdftIhQ@G4fvg-0gy;gw_MQ=kKR4>kAJ&w7|6-%e+iNTo_J2KSkc`f6p%0L z+$3M#3A7CjQ~_(0WK)9$0#t!m?ixHMc?Ons{DOdj1%h+|l1)+F&zS|Xb1d;XDX^sN z69lv;@9l@r-WmDFOOFqdY>FPci`@U!r}Nx@aob{2V6pFU*t<`*w~Na7{h30; zR=I2l3gN0VXK^Pu+^?F@w^VR9bA=b`#+Z}o!?;oAzSHwN?Pr{lB;$v z5moU=GE*6@iocJobUVmo2RC8Q-bout$nM^HctwV>D0{Dvp2Dzv;Y7A M07*qoM6N<$f>-wnX8-^I literal 5192 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 diff --git a/app/javascript/icons/favicon-48x48.png b/app/javascript/icons/favicon-48x48.png index 0aac1ee5b8358646f0d626d9bd4998442d103eb9..259676c0a9217ed353269ec3dccb50cca399dfba 100644 GIT binary patch delta 1664 zcmV-`27mdvIFJpHBYy^0Nkl2XosBb`&X}1U z@-bhK!X zu0|gi>O>-@ue0}gCE*@UR zxei;fk%6J2tA9b%REAJp5rSqXJc9D#5bCQ#DAXv2MpJ@zA;6*dOB}WUhQjKVVf^?* z9MLEe6OREud>=dXJ!)^})DS-UFos}|?->U0&p&bO-y4Bb6?P~-7w-Wj@Rq9hF%VAG zkIz1hVX*n&{U|hh|J}X2!#tRnhK4x1M+1D1#<1DE<9`x|uXqsWs8(Nufr0q!(u{y_^wecUJS(g)jnh35bAzI?*aO-8_Dc-)mEMFmxz3Bf=}@>`1{TlrLp2}vi!~44ej_Y( z*RBX0a!7JrQ+Ys+Ycl%+C{`}<^4(O=7?wzeP#^^H0QwO@B{!9BQuIfBE^4_)7L}SmJWjoPGga zET9_{kL(cxKKnRK`Y${a5d2?%j*|Y~9pd%B`kcN#g9UW+02>RiXLo@>8u0!*A=2No z-6!~;eiSDC?Hj$)0Ex@V>YkYhU|*PI&*}sL3-Cz-f~3D|i+G@q-V2fb_6_;VnwRkfwJf#Q)}9x>pp0O{}C3^;HeF9q2Y^g1vcx0zr7C`wdz$FH}L;Ks- zN&-F&N?eYT(qiSWLaEL7D5=e$I3Nx1lYVVcJJu}e>Br3aPSW4HwpY0Rmn=Zya?+Y| z_;Vno;YKB;2?Q*_B?i3d7rYU|0(#^D^bV{^O?M{(EJ=-5DannXIIu$&;1j%&vVV1r zEFdu8j^&}2OZYvI{^vL)sR0xRw)e^c1aG8lUEM7Ypm%(;X5sWc{|ox*Z0p1Sfj}DY z-Wxu_8zJ(5PXeTGN&4?e)3IZH=wBZLGOE-jES%ETkBKGCf;Upil}6$ElgnC2UwP;s zvl#Gywe^HE(aq*MH~Tcb##VZ4FsN7;@8_8nQ7jyRPkQ4jHH4n{qwe zfBW~{K9_&ndm{j@lUI5syoHtMcS(1C zwshx|PJNP|>~e%uJ@mUqIdc7_E35QIxU#WP&P)aRTf}gunQ&%40Hp)3xql;bTsX2L z2vH4CbrX(s2&fvEAe|YXbfy;xM`jm%kAmmmb2Y|&3*$VLj`TJ7yq7!D>qSLs8fJT`7iWn|6LwbtYqF#<;AAqW! zXi(sU8P%Y{rgSS|iy9b?^ha7macnfK$VZ@RAWm^~JF`V*G92OXop5Vx61PPca2#1p zZPAV3DEwXopMiq^Dv?$R9Puz~b2!YHP-EaQH3wf(Q&82yM{t%HgEI(Dv_#rfjlE(D z^d|=YVrmHPAco*+YVa3f<(_}zG4NBPe;53>0)`(Bm)!QKgna>obe_C{6JZko0000< KMNUMnLSTX;wlZS? literal 7225 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 diff --git a/public/chuckya.png b/public/chuckya.png new file mode 100644 index 0000000000000000000000000000000000000000..eb6d3810e85b527dce41c993c1220d27698aabd5 GIT binary patch literal 76264 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 Date: Thu, 9 May 2024 23:35:20 -0500 Subject: [PATCH 113/658] Fix video sizing in edit media modal --- .../flavours/glitch/features/ui/components/focal_point_modal.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx index 0ee84dd0c2..ac0ad4cd92 100644 --- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx @@ -408,7 +408,6 @@ class FocalPointModal extends ImmutablePureComponent { blurhash={media.get('blurhash')} src={media.get('url')} detailed - inline editable /> )} From 5a3062f723abefe4ec49898256e1d81b01fbf6f4 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 10 May 2024 10:00:02 +0200 Subject: [PATCH 114/658] Pass the CodeCov token from the secret to the action (#30219) --- .github/workflows/test-ruby.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index b28f5261c2..84b9075708 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -145,6 +145,8 @@ jobs: uses: codecov/codecov-action@v4 with: files: coverage/lcov/mastodon.lcov + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} test-e2e: name: End to End testing From 6819bcc4b6772075a8fd45b995b9e1bf92ef7868 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 11:18:52 +0200 Subject: [PATCH 115/658] Update dependency glob to v10.3.14 (#30230) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 95a3923e25..22f81166f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8882,17 +8882,17 @@ __metadata: linkType: hard "glob@npm:^10.2.2, glob@npm:^10.2.6, glob@npm:^10.3.10, glob@npm:^10.3.7": - version: 10.3.12 - resolution: "glob@npm:10.3.12" + version: 10.3.14 + resolution: "glob@npm:10.3.14" dependencies: foreground-child: "npm:^3.1.0" jackspeak: "npm:^2.3.6" minimatch: "npm:^9.0.1" minipass: "npm:^7.0.4" - path-scurry: "npm:^1.10.2" + path-scurry: "npm:^1.11.0" bin: glob: dist/esm/bin.mjs - checksum: 10c0/f60cefdc1cf3f958b2bb5823e1b233727f04916d489dc4641d76914f016e6704421e06a83cbb68b0cb1cb9382298b7a88075b844ad2127fc9727ea22b18b0711 + checksum: 10c0/19126e53b99c94dea9b3509500e22b325e24d2674523fc95b9fe710f1549ad7e091fbb0704c325c53d3a172fc21a8251acce5395c4f3efd872a2e65a376c82a1 languageName: node linkType: hard @@ -12770,13 +12770,13 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.10.2": - version: 1.10.2 - resolution: "path-scurry@npm:1.10.2" +"path-scurry@npm:^1.11.0": + version: 1.11.0 + resolution: "path-scurry@npm:1.11.0" dependencies: lru-cache: "npm:^10.2.0" minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10c0/d723777fbf9627f201e64656680f66ebd940957eebacf780e6cce1c2919c29c116678b2d7dbf8821b3a2caa758d125f4444005ccec886a25c8f324504e48e601 + checksum: 10c0/a5cd5dfbc6d5bb01d06bc2eb16ccdf303d617865438a21fe15431b8ad334f23351f73259abeb7e4be56f9c68d237b26b4dba51c78b508586035dfc2b55085493 languageName: node linkType: hard From 6ccee2600bf8920131f9b4ad5706cf632262556b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 11:19:06 +0200 Subject: [PATCH 116/658] Update dependency rubocop to v1.63.5 (#30225) 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 435144700f..9df960e618 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -640,7 +640,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 8) rspec-support (3.13.1) - rubocop (1.63.4) + rubocop (1.63.5) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) From c36a8786c10c36e5181c9c53d848fa8e7b24b692 Mon Sep 17 00:00:00 2001 From: Chee Aun Date: Fri, 10 May 2024 17:19:27 +0800 Subject: [PATCH 117/658] Fix typo (#30224) --- .../mastodon/features/notifications/components/notification.jsx | 2 +- app/javascript/mastodon/locales/en.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx index caf7f9bdc1..69084c2111 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.jsx +++ b/app/javascript/mastodon/features/notifications/components/notification.jsx @@ -41,7 +41,7 @@ const messages = defineMessages({ adminSignUp: { id: 'notification.admin.sign_up', defaultMessage: '{name} signed up' }, adminReport: { id: 'notification.admin.report', defaultMessage: '{name} reported {target}' }, relationshipsSevered: { id: 'notification.relationships_severance_event', defaultMessage: 'Lost connections with {name}' }, - moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'Your have received a moderation warning' }, + moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'You have received a moderation warning' }, }); const notificationForScreenReader = (intl, message, timestamp) => { diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 9d127b6b03..56e4612c1c 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -474,7 +474,7 @@ "notification.follow_request": "{name} has requested to follow you", "notification.mention": "{name} mentioned you", "notification.moderation-warning.learn_more": "Learn more", - "notification.moderation_warning": "Your have received a moderation warning", + "notification.moderation_warning": "You have received a moderation warning", "notification.moderation_warning.action_delete_statuses": "Some of your posts have been removed.", "notification.moderation_warning.action_disable": "Your account has been disabled.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Some of your posts have been marked as sensitive.", From 0a4a93038fa08e0f64f3b1f267853f38f41cd0cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 09:22:47 +0000 Subject: [PATCH 118/658] Update Yarn to v4.2.2 (#30220) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- streaming/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3abc11c34b..d884883331 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/mastodon", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.2.1", + "packageManager": "yarn@4.2.2", "engines": { "node": ">=18" }, diff --git a/streaming/package.json b/streaming/package.json index f08d2a4c2d..cf1fe4ba69 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/streaming", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.2.1", + "packageManager": "yarn@4.2.2", "engines": { "node": ">=18" }, From 1aa3976f280efed1ae4c72c1ac58e3e4ff9061f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 11:23:45 +0200 Subject: [PATCH 119/658] Update dependency pino-http to v10.1.0 (#30199) 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 22f81166f8..28cf500466 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13004,14 +13004,14 @@ __metadata: linkType: hard "pino-http@npm:^10.0.0": - version: 10.0.0 - resolution: "pino-http@npm:10.0.0" + version: 10.1.0 + resolution: "pino-http@npm:10.1.0" dependencies: get-caller-file: "npm:^2.0.5" pino: "npm:^9.0.0" pino-std-serializers: "npm:^7.0.0" process-warning: "npm:^3.0.0" - checksum: 10c0/40d2dcb2bc0c51f1ce45d3d7144c54f087fe1a122d82d0f497d65656151a1603a64f82f62d7fc6a3c172754c5a5cf6105b3096620eece31cefbc8cf95b26c062 + checksum: 10c0/d97691f2ee248b0aca0e49169d0c7ca0d4c604ee57b63ae264a6f9914fc7277cace74686d5088a876f8152a8d5b8211af904b2d24a516728a662de0e9cc79e9f languageName: node linkType: hard From 3a5a1b2e5838d8915bd2d08e5d3ea363d66b611e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 09:25:07 +0000 Subject: [PATCH 120/658] Update dependency node to 20.13 (#30211) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 7795cadb57..973f49d55c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.12 +20.13 From c9557bdd3bc7c67f6513295b0ab633cfca8cbfdd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 11:34:48 +0200 Subject: [PATCH 121/658] New Crowdin Translations (automated) (#30215) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/gl.json | 8 +-- app/javascript/mastodon/locales/hi.json | 5 ++ app/javascript/mastodon/locales/ie.json | 29 ++++++++ app/javascript/mastodon/locales/lt.json | 93 +++++++++++++++---------- app/javascript/mastodon/locales/lv.json | 35 ++++++++-- config/locales/devise.ia.yml | 25 +++++++ config/locales/doorkeeper.ia.yml | 4 ++ config/locales/doorkeeper.ie.yml | 1 + config/locales/doorkeeper.lt.yml | 50 ++++++------- config/locales/gl.yml | 10 +-- config/locales/ia.yml | 44 ++++++++++++ config/locales/ie.yml | 2 + config/locales/ko.yml | 1 + config/locales/lt.yml | 5 ++ config/locales/lv.yml | 21 ++++++ config/locales/pt-BR.yml | 1 + config/locales/ro.yml | 9 +++ config/locales/simple_form.ar.yml | 5 ++ config/locales/simple_form.bg.yml | 2 + config/locales/simple_form.de.yml | 4 +- config/locales/simple_form.hu.yml | 2 +- config/locales/simple_form.ia.yml | 2 + config/locales/simple_form.it.yml | 2 + config/locales/simple_form.ko.yml | 3 + config/locales/simple_form.lt.yml | 2 +- config/locales/simple_form.nn.yml | 3 +- config/locales/simple_form.pt-BR.yml | 5 ++ config/locales/simple_form.ro.yml | 1 + config/locales/simple_form.sq.yml | 2 + config/locales/uk.yml | 2 +- 30 files changed, 296 insertions(+), 82 deletions(-) diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 49802ac488..88d4f5f60e 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -2,7 +2,7 @@ "about.blocks": "Servidores suxeitos a moderación", "about.contact": "Contacto:", "about.disclaimer": "Mastodon é software libre, de código aberto, e unha marca comercial de Mastodon gGmbH.", - "about.domain_blocks.no_reason_available": "Motivo non indicado. ", + "about.domain_blocks.no_reason_available": "Motivo non indicado", "about.domain_blocks.preamble": "Mastodon de xeito xeral permíteche ver contidos doutros servidores do fediverso e interactuar coas súas usuarias. Estas son as excepcións que se estabeleceron neste servidor en particular.", "about.domain_blocks.silenced.explanation": "Por defecto non verás perfís e contido desde este servidor, a menos que mires de xeito explícito ou optes por seguir ese contido ou usuaria.", "about.domain_blocks.silenced.title": "Limitado", @@ -115,7 +115,7 @@ "closed_registrations_modal.find_another_server": "Atopa outro servidor", "closed_registrations_modal.preamble": "Mastodon é descentralizado, así que non importa onde crees a conta, poderás seguir e interactuar con calquera conta deste servidor. Incluso podes ter o teu servidor!", "closed_registrations_modal.title": "Crear conta en Mastodon", - "column.about": "Acerca de", + "column.about": "Sobre", "column.blocks": "Usuarias bloqueadas", "column.bookmarks": "Marcadores", "column.community": "Cronoloxía local", @@ -322,7 +322,7 @@ "follow_suggestions.view_all": "Ver todas", "follow_suggestions.who_to_follow": "A quen seguir", "followed_tags": "Cancelos seguidos", - "footer.about": "Acerca de", + "footer.about": "Sobre", "footer.directory": "Directorio de perfís", "footer.get_app": "Descarga a app", "footer.invite": "Convidar persoas", @@ -441,7 +441,7 @@ "mute_modal.title": "Acalar usuaria?", "mute_modal.you_wont_see_mentions": "Non verás as publicacións que a mencionen.", "mute_modal.you_wont_see_posts": "Seguirá podendo ler as túas publicacións, pero non verás as súas.", - "navigation_bar.about": "Acerca de", + "navigation_bar.about": "Sobre", "navigation_bar.advanced_interface": "Abrir coa interface web avanzada", "navigation_bar.blocks": "Usuarias bloqueadas", "navigation_bar.bookmarks": "Marcadores", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index 372eb09fa7..5dc99dd76e 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -205,6 +205,10 @@ "dismissable_banner.dismiss": "डिसमिस", "dismissable_banner.explore_links": "इन समाचारों के बारे में लोगों द्वारा इस पर और डेसेंट्रलीसेड नेटवर्क के अन्य सर्वरों पर अभी बात की जा रही है।", "dismissable_banner.explore_tags": "ये हैशटैग अभी इस पर और डेसेंट्रलीसेड नेटवर्क के अन्य सर्वरों पर लोगों के बीच कर्षण प्राप्त कर रहे हैं।", + "domain_block_modal.block": "सर्वर ब्लॉक करें", + "domain_block_modal.title": "डोमेन ब्लॉक करें", + "domain_pill.server": "सर्वर", + "domain_pill.username": "यूज़रनेम", "embed.instructions": "अपने वेबसाइट पर, निचे दिए कोड को कॉपी करके, इस स्टेटस को एम्बेड करें", "embed.preview": "यह ऐसा दिखेगा :", "emoji_button.activity": "गतिविधि", @@ -274,6 +278,7 @@ "follow_request.authorize": "अधिकार दें", "follow_request.reject": "अस्वीकार करें", "follow_requests.unlocked_explanation": "हालाँकि आपका खाता लॉक नहीं है, फिर भी {domain} डोमेन स्टाफ ने सोचा कि आप इन खातों के मैन्युअल अनुरोधों की समीक्षा करना चाहते हैं।", + "follow_suggestions.dismiss": "दोबारा न दिखाएं", "followed_tags": "फॉलो किए गए हैशटैग्स", "footer.about": "अबाउट", "footer.directory": "प्रोफाइल्स डायरेक्टरी", diff --git a/app/javascript/mastodon/locales/ie.json b/app/javascript/mastodon/locales/ie.json index 8d491412c0..7bd91ca0f9 100644 --- a/app/javascript/mastodon/locales/ie.json +++ b/app/javascript/mastodon/locales/ie.json @@ -212,13 +212,20 @@ "domain_block_modal.block_account_instead": "Altrimen, bloccar @{name}", "domain_block_modal.they_can_interact_with_old_posts": "Persones de ti servitor posse interacter con tui old postas.", "domain_block_modal.they_cant_follow": "Nequi de ti-ci servitor posse sequer te.", + "domain_block_modal.they_wont_know": "Ne va esser conscient pri li bloccada.", + "domain_block_modal.title": "Bloccar dominia?", + "domain_block_modal.you_will_lose_followers": "Omni tui sequitores de ti-ci servitor va esser efaciat.", + "domain_block_modal.you_wont_see_posts": "Tu ne va vider postas ni notificationes de usatores sur ti-ci servitor.", + "domain_pill.activitypub_lets_connect": "It possibilisa tui conexiones e interactiones con persones ne solmen sur Mastodon, ma anc tra diferent social aplis.", "domain_pill.activitypub_like_language": "ActivityPub es li lingue usat de Mastodon por parlar con altri social retages.", "domain_pill.server": "Servitor", "domain_pill.their_handle": "Identificator:", "domain_pill.their_server": "Su digital hem e omni su postas.", + "domain_pill.their_username": "Su unic identificator sur su servitor. It es possibil que altri servitores va haver usatores con li sam nómine.", "domain_pill.username": "Usator-nómine", "domain_pill.whats_in_a_handle": "Ex quo consiste un identificator?", "domain_pill.your_handle": "Tui identificator:", + "domain_pill.your_username": "Tui unic identificator sur ti-ci servitor. It es possibil que altri servitores va haver usatores con li sam nómine.", "embed.instructions": "Inbedar ti-ci posta per copiar li code in infra.", "embed.preview": "Vi qualmen it va aspecter:", "emoji_button.activity": "Activitá", @@ -286,6 +293,7 @@ "filter_modal.select_filter.subtitle": "Usar un existent categorie o crear nov", "filter_modal.select_filter.title": "Filtrar ti-ci posta", "filter_modal.title.status": "Filtrar un posta", + "filtered_notifications_banner.mentions": "{count, plural, one {mention} other {mentiones}}", "filtered_notifications_banner.pending_requests": "Notificationes de {count, plural, =0 {nequi} one {un person} other {# persones}} quel tu possibilmen conosse", "filtered_notifications_banner.title": "Filtrat notificationes", "firehose.all": "Omno", @@ -296,6 +304,8 @@ "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 employates", "follow_suggestions.dismiss": "Ne monstrar plu", + "follow_suggestions.featured_longer": "Selectet manualmen del equip de {domain}", + "follow_suggestions.friends_of_friends_longer": "Populari ínter li persones queles tu seque", "follow_suggestions.hints.featured": "Ti-ci profil ha esset selectet directmen del equip de {domain}.", "follow_suggestions.hints.friends_of_friends": "Ti-ci profil es populari ínter tis qui tu seque.", "follow_suggestions.hints.most_followed": "Ti-ci profil es un del max sequet sur {domain}.", @@ -303,6 +313,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Ti-ci profil es simil al profiles queles tu ha recentmen sequet.", "follow_suggestions.personalized_suggestion": "Personalisat suggestion", "follow_suggestions.popular_suggestion": "Populari suggestion", + "follow_suggestions.popular_suggestion_longer": "Populari sur {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Simil a profiles queles tu sequet recentmen", "follow_suggestions.view_all": "Vider omnicos", "follow_suggestions.who_to_follow": "Persones a sequer", "followed_tags": "Sequet hashtags", @@ -423,6 +435,8 @@ "mute_modal.they_can_mention_and_follow": "Posse mentionar e sequer te, ma va esser ínvisibil a te.", "mute_modal.they_wont_know": "Ne va esser conscient pri li silentation.", "mute_modal.title": "Silentiar usator?", + "mute_modal.you_wont_see_mentions": "Tu ne va vider postas mentionant li usator.", + "mute_modal.you_wont_see_posts": "Ne posse vider tui postas e inversi.", "navigation_bar.about": "Information", "navigation_bar.advanced_interface": "Aperter in li web-interfacie avansat", "navigation_bar.blocks": "Bloccat usatores", @@ -455,10 +469,23 @@ "notification.follow": "{name} sequet te", "notification.follow_request": "{name} ha petit sequer te", "notification.mention": "{name} mentionat te", + "notification.moderation-warning.learn_more": "Aprender plu", + "notification.moderation_warning": "Tu ha recivet un moderatori advertiment", + "notification.moderation_warning.action_delete_statuses": "Alcun de tui postas ha esset efaciat.", + "notification.moderation_warning.action_disable": "Tui conto ha esset desactivisat.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Alcun de tui postas ha esset marcat quam sensitiv.", + "notification.moderation_warning.action_none": "Tui conto ha recivet un moderatori advertiment.", + "notification.moderation_warning.action_sensitive": "Desde nu tui postas va esser marcat quam sensitiv.", + "notification.moderation_warning.action_silence": "Tui conto ha esset limitat.", + "notification.moderation_warning.action_suspend": "Tui conto ha esset suspendet.", "notification.own_poll": "Tui balotation ha finit", "notification.poll": "Un balotation in quel tu votat ha finit", "notification.reblog": "{name} boostat tui posta", + "notification.relationships_severance_event": "Perdit conexiones con {name}", + "notification.relationships_severance_event.account_suspension": "Un admin de {from} ha suspendet {target}, dunc con ti person tu ne plu posse reciver actualisationes ni far interactiones.", + "notification.relationships_severance_event.domain_block": "Un admin de {from} ha bloccat {target}, includente {followersCount} de tui sequitores e {followingCount, plural, one {# conto} other {# contos}} sequet de te.", "notification.relationships_severance_event.learn_more": "Aprender plu", + "notification.relationships_severance_event.user_domain_block": "Tu ha bloccat {target}, efaciante {followersCount} de tui sequitores e {followingCount, plural, one {# conto} other {# contos}} sequet de te.", "notification.status": "{name} just postat", "notification.update": "{name} modificat un posta", "notification_requests.accept": "Acceptar", @@ -472,6 +499,7 @@ "notifications.column_settings.alert": "Notificationes sur li computator", "notifications.column_settings.favourite": "Favorites:", "notifications.column_settings.filter_bar.advanced": "Monstrar omni categories", + "notifications.column_settings.filter_bar.category": "Rapid filtre-barre", "notifications.column_settings.follow": "Nov sequitores:", "notifications.column_settings.follow_request": "Nov petitiones de sequer:", "notifications.column_settings.mention": "Mentiones:", @@ -707,6 +735,7 @@ "status.reblog": "Boostar", "status.reblog_private": "Boostar con li original visibilitá", "status.reblogged_by": "{name} boostat", + "status.reblogs": "{count, plural, one {boost} other {boosts}}", "status.reblogs.empty": "Ancor nequi ha boostat ti-ci posta. Quande alqui fa it, ilu va aparir ci.", "status.redraft": "Deleter & redacter", "status.remove_bookmark": "Remover marcator", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 083a922012..798b24569f 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -1,7 +1,7 @@ { "about.blocks": "Prižiūrimi serveriai", "about.contact": "Kontaktai:", - "about.disclaimer": "Mastodon – nemokama atvirojo kodo programa ir Mastodon gGmbH prekės ženklas.", + "about.disclaimer": "Mastodon – tai nemokama atvirojo kodo programinė įranga ir Mastodon gGmbH prekės ženklas.", "about.domain_blocks.no_reason_available": "Priežastis nepateikta", "about.domain_blocks.preamble": "Mastodon paprastai leidžia peržiūrėti turinį ir bendrauti su naudotojais iš bet kurio kito fediverse esančio serverio. Šios yra išimtys, kurios buvo padarytos šiame konkrečiame serveryje.", "about.domain_blocks.silenced.explanation": "Paprastai nematysi profilių ir turinio iš šio serverio, nebent jį aiškiai ieškosi arba pasirinksi jį sekdamas (-a).", @@ -30,7 +30,7 @@ "account.endorse": "Rodyti profilyje", "account.featured_tags.last_status_at": "Paskutinis įrašas {date}", "account.featured_tags.last_status_never": "Nėra įrašų", - "account.featured_tags.title": "{name} rekomenduojami saitažodžiai", + "account.featured_tags.title": "{name} rodomi saitažodžiai", "account.follow": "Sekti", "account.follow_back": "Sekti atgal", "account.followers": "Sekėjai", @@ -38,13 +38,13 @@ "account.followers_counter": "{count, plural, one {{counter} sekėjas} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", "account.following": "Sekama", "account.following_counter": "{count, plural, one {{counter} sekimas} few {{counter} sekimai} many {{counter} sekimo} other {{counter} sekimų}}", - "account.follows.empty": "Šis (-i) naudotojas (-a) dar nieko neseka.", + "account.follows.empty": "Šis naudotojas dar nieko neseka.", "account.go_to_profile": "Eiti į profilį", "account.hide_reblogs": "Slėpti pakėlimus iš @{name}", "account.in_memoriam": "Atminimui.", "account.joined_short": "Prisijungė", "account.languages": "Keisti prenumeruojamas kalbas", - "account.link_verified_on": "Šios nuorodos nuosavybė buvo patikrinta {date}.", + "account.link_verified_on": "Šios nuorodos nuosavybė buvo patikrinta {date}", "account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.", "account.media": "Medija", "account.mention": "Paminėti @{name}", @@ -59,7 +59,7 @@ "account.posts": "Įrašai", "account.posts_with_replies": "Įrašai ir atsakymai", "account.report": "Pranešti apie @{name}", - "account.requested": "Laukiama patvirtinimo. Spustelėk, jei nori atšaukti sekimo prašymą.", + "account.requested": "Laukiama patvirtinimo. Spustelėk, jei nori atšaukti sekimo prašymą", "account.requested_follow": "{name} paprašė tave sekti", "account.share": "Bendrinti @{name} profilį", "account.show_reblogs": "Rodyti pakėlimus iš @{name}", @@ -82,7 +82,7 @@ "admin.impact_report.instance_followers": "Sekėjai, kuriuos prarastų mūsų naudotojai", "admin.impact_report.instance_follows": "Sekėjai, kuriuos prarastų jų naudotojai", "admin.impact_report.title": "Poveikio apibendrinimas", - "alert.rate_limited.message": "Pabandyk vėliau po {retry_time, time, medium}.", + "alert.rate_limited.message": "Bandyk vėliau po {retry_time, time, medium}.", "alert.rate_limited.title": "Sparta ribota.", "alert.unexpected.message": "Įvyko netikėta klaida.", "alert.unexpected.title": "Ups!", @@ -92,7 +92,12 @@ "block_modal.remote_users_caveat": "Paprašysime serverio {domain} gerbti tavo sprendimą. Tačiau atitiktis negarantuojama, nes kai kurie serveriai gali skirtingai tvarkyti blokavimus. Vieši įrašai vis tiek gali būti matomi neprisijungusiems naudotojams.", "block_modal.show_less": "Rodyti mažiau", "block_modal.show_more": "Rodyti daugiau", - "boost_modal.combo": "Galima paspausti {combo}, kad praleisti kitą kartą.", + "block_modal.they_cant_mention": "Jie negali tave paminėti ar sekti.", + "block_modal.they_cant_see_posts": "Jie negali matyti tavo įrašus, o tu nematysi jų.", + "block_modal.they_will_know": "Jie mato, kad yra užblokuoti.", + "block_modal.title": "Blokuoti naudotoją?", + "block_modal.you_wont_see_mentions": "Nematysi įrašus, kuriuose jie paminimi.", + "boost_modal.combo": "Galima paspausti {combo}, kad praleisti tai kitą kartą", "bundle_column_error.copy_stacktrace": "Kopijuoti klaidos ataskaitą", "bundle_column_error.error.body": "Paprašytos puslapio nepavyko atvaizduoti. Tai gali būti dėl mūsų kodo klaidos arba naršyklės suderinamumo problemos.", "bundle_column_error.error.title": "O, ne!", @@ -117,7 +122,7 @@ "column.direct": "Privatūs paminėjimai", "column.directory": "Naršyti profilius", "column.domain_blocks": "Užblokuoti domenai", - "column.favourites": "Mėgstamiausi", + "column.favourites": "Mėgstami", "column.firehose": "Tiesioginiai srautai", "column.follow_requests": "Sekimo prašymai", "column.home": "Pagrindinis", @@ -144,7 +149,7 @@ "compose.saved.body": "Įrašas išsaugotas.", "compose_form.direct_message_warning_learn_more": "Sužinoti daugiau", "compose_form.encryption_warning": "Mastodon įrašai nėra visapusiškai šifruojami. Per Mastodon nesidalyk jokia slapta informacija.", - "compose_form.hashtag_warning": "Šis įrašas nebus įtraukta į jokį saitažodį, nes ji nėra vieša. Tik viešų įrašų galima ieškoti pagal saitažodį.", + "compose_form.hashtag_warning": "Šis įrašas nebus įtrauktas į jokį saitažodį, nes ji nėra vieša. Tik viešų įrašų galima ieškoti pagal saitažodį.", "compose_form.lock_disclaimer": "Tavo paskyra nėra {locked}. Bet kas gali sekti tave ir peržiūrėti tik sekėjams skirtus įrašus.", "compose_form.lock_disclaimer.lock": "užrakinta", "compose_form.placeholder": "Kas tavo mintyse?", @@ -152,7 +157,7 @@ "compose_form.poll.multiple": "Keli pasirinkimai", "compose_form.poll.option_placeholder": "{number} parinktis", "compose_form.poll.single": "Pasirinkti vieną", - "compose_form.poll.switch_to_multiple": "Keisti apklausą, kad būtų galima pasirinkti kelis pasirinkimus.", + "compose_form.poll.switch_to_multiple": "Keisti apklausą, kad būtų galima pasirinkti kelis pasirinkimus", "compose_form.poll.switch_to_single": "Keisti apklausą, kad būtų galima pasirinkti vieną pasirinkimą", "compose_form.poll.type": "Stilius", "compose_form.publish": "Skelbti", @@ -172,16 +177,17 @@ "confirmations.delete_list.message": "Ar tikrai nori visam laikui ištrinti šį sąrašą?", "confirmations.discard_edit_media.confirm": "Atmesti", "confirmations.discard_edit_media.message": "Turi neišsaugotų medijos aprašymo ar peržiūros pakeitimų, vis tiek juos atmesti?", + "confirmations.domain_block.confirm": "Blokuoti serverį", "confirmations.domain_block.message": "Ar tikrai, tikrai nori užblokuoti visą {domain}? Daugeliu atvejų užtenka kelių tikslinių blokavimų arba nutildymų. Šio domeno turinio nematysi jokiose viešose laiko skalėse ar pranešimuose. Tavo sekėjai iš to domeno bus pašalinti.", "confirmations.edit.confirm": "Redaguoti", "confirmations.edit.message": "Redaguojant dabar, bus perrašyta šiuo metu kuriama žinutė. Ar tikrai nori tęsti?", "confirmations.logout.confirm": "Atsijungti", "confirmations.logout.message": "Ar tikrai nori atsijungti?", "confirmations.mute.confirm": "Nutildyti", - "confirmations.redraft.confirm": "Ištrinti ir parengti iš naujo", - "confirmations.redraft.message": "Ar tikrai nori ištrinti šį įrašą ir parengti jį iš naujo kaip juodraštį? Bus prarastos mėgstamiausios ir pakėlimai, o atsakymai į originalinį įrašą taps liekamojais.", + "confirmations.redraft.confirm": "Ištrinti ir perrašyti", + "confirmations.redraft.message": "Ar tikrai nori ištrinti šį įrašą ir parašyti jį iš naujo? Bus prarastos mėgstamai ir pakėlimai, o atsakymai į originalinį įrašą taps liekamojais.", "confirmations.reply.confirm": "Atsakyti", - "confirmations.reply.message": "Atsakant dabar, bus perrašyta metu kuriama žinutė. Ar tikrai nori tęsti?", + "confirmations.reply.message": "Atsakant dabar, bus perrašyta šiuo metu kuriama žinutė. Ar tikrai nori tęsti?", "confirmations.unfollow.confirm": "Nebesekti", "confirmations.unfollow.message": "Ar tikrai nori nebesekti {name}?", "conversation.delete": "Ištrinti pokalbį", @@ -196,34 +202,42 @@ "directory.new_arrivals": "Nauji atvykėliai", "directory.recently_active": "Neseniai aktyvus (-i)", "disabled_account_banner.account_settings": "Paskyros nustatymai", - "disabled_account_banner.text": "Tavo paskyra {disabledAccount} šiuo metu išjungta.", - "dismissable_banner.community_timeline": "Tai – naujausi vieši įrašai, kuriuos paskelbė žmonės, kurių paskyros talpinamos {domain}.", + "disabled_account_banner.text": "Tavo paskyra {disabledAccount} šiuo metu yra išjungta.", + "dismissable_banner.community_timeline": "Tai – naujausi vieši įrašai iš žmonių, kurių paskyros talpinamos {domain}.", "dismissable_banner.dismiss": "Atmesti", "dismissable_banner.explore_links": "Tai – naujienos, kuriomis šiandien daugiausiai bendrinamasi socialiniame žiniatinklyje. Naujesnės naujienų istorijos, kurias paskelbė daugiau skirtingų žmonių, vertinamos aukščiau.", "dismissable_banner.explore_statuses": "Tai – įrašai iš viso socialinio žiniatinklio, kurie šiandien sulaukia daug dėmesio. Naujesni įrašai, turintys daugiau pakėlimų ir mėgstamų, vertinami aukščiau.", "dismissable_banner.explore_tags": "Tai – saitažodžiai, kurie šiandien sulaukia daug dėmesio socialiniame žiniatinklyje. Saitažodžiai, kuriuos naudoja daugiau skirtingų žmonių, vertinami aukščiau.", - "dismissable_banner.public_timeline": "Tai – naujausi vieši įrašai, kuriuos socialiniame žiniatinklyje paskelbė žmonės, sekantys {domain}.", - "domain_pill.activitypub_lets_connect": "Tai leidžia tau bendrauti su žmonėmis ne tik Mastodon, bet ir įvairiose socialinėse programėlėse.", - "domain_pill.activitypub_like_language": "ActivityPub – tarsi kalba, kuria Mastodon kalba su kitais socialiniais tinklais.", + "dismissable_banner.public_timeline": "Tai – naujausi vieši įrašai iš žmonių socialiniame žiniatinklyje, kuriuos seka {domain} žmonės.", + "domain_block_modal.block": "Blokuoti serverį", + "domain_block_modal.block_account_instead": "Blokuoti {name} vietoj to", + "domain_block_modal.they_can_interact_with_old_posts": "Žmonės iš šio serverio gali sąveikauti su tavo senomis įrašomis.", + "domain_block_modal.they_cant_follow": "Niekas iš šio serverio negali tavęs sekti.", + "domain_block_modal.they_wont_know": "Jie nežinos, kad buvo užblokuoti.", + "domain_block_modal.title": "Blokuoti domeną?", + "domain_block_modal.you_will_lose_followers": "Visi tavo sekėjai iš šio serverio bus pašalinti.", + "domain_block_modal.you_wont_see_posts": "Nematysi naudotojų įrašų ar pranešimų šiame serveryje.", + "domain_pill.activitypub_lets_connect": "Tai leidžia tau sąveikauti su žmonėmis ne tik Mastodon, bet ir įvairiose socialinėse programėlėse.", + "domain_pill.activitypub_like_language": "ActivityPub – tai tarsi kalba, kuria Mastodon kalba su kitais socialiniais tinklais.", "domain_pill.server": "Serveris", "domain_pill.their_handle": "Jų socialinis medijos vardas:", "domain_pill.their_server": "Jų skaitmeniniai namai, kuriuose saugomi visi jų įrašai.", "domain_pill.their_username": "Jų unikalus identifikatorius jų serveryje. Skirtinguose serveriuose galima rasti naudotojų, turinčių tą patį naudotojo vardą.", "domain_pill.username": "Naudotojo vardas", "domain_pill.whats_in_a_handle": "Kas yra socialiniame medijos varde?", - "domain_pill.who_they_are": "Kadangi socialines medijos vardai nurodo, kas ir kur jie yra, galima bendrauti su žmonėmis visame socialiniame tinkle, kuriame yra .", - "domain_pill.who_you_are": "Kadangi tavo socialinis medijos vardas nurodo, kas esi ir kur esi, žmonės gali bendrauti su tavimi visame socialiniame tinkle, kurį sudaro .", + "domain_pill.who_they_are": "Kadangi socialines medijos vardai nurodo, kas žmogus yra ir kur jie yra, gali sąveikauti su žmonėmis visame socialiniame žiniatinklyje, kurį sudaro .", + "domain_pill.who_you_are": "Kadangi tavo socialinis medijos vardas nurodo, kas esi ir kur esi, žmonės gali sąveikauti su tavimi visame socialiniame tinkle, kurį sudaro .", "domain_pill.your_handle": "Tavo socialinis medijos vardas:", "domain_pill.your_server": "Tavo skaitmeniniai namai, kuriuose saugomi visi tavo įrašai. Nepatinka šis? Bet kada perkelk serverius ir atsivesk ir savo sekėjus.", - "domain_pill.your_username": "Tavo unikalus identifikatorius šiame serveryje. Skirtinguose serveriuose galima rasti naudotojų, turinčių tą patį naudotojo vardą.", + "domain_pill.your_username": "Tavo unikalus identifikatorius šiame serveryje. Skirtinguose serveriuose galima rasti naudotojų su tuo pačiu naudotojo vardu.", "embed.instructions": "Įterpk šį įrašą į savo svetainę nukopijavus (-usi) toliau pateiktą kodą.", - "embed.preview": "Štai, kaip tai atrodys:", + "embed.preview": "Štai kaip tai atrodys:", "emoji_button.activity": "Veikla", "emoji_button.clear": "Išvalyti", "emoji_button.custom": "Pasirinktinis", "emoji_button.flags": "Vėliavos", "emoji_button.food": "Maistas ir gėrimai", - "emoji_button.label": "Įterpti veidelius", + "emoji_button.label": "Įterpti jaustuką", "emoji_button.nature": "Gamta", "emoji_button.not_found": "Nerasta jokių tinkamų jaustukų.", "emoji_button.objects": "Objektai", @@ -234,12 +248,12 @@ "emoji_button.symbols": "Simboliai", "emoji_button.travel": "Kelionės ir vietos", "empty_column.account_hides_collections": "Šis (-i) naudotojas (-a) pasirinko nepadaryti šią informaciją prieinamą.", - "empty_column.account_suspended": "Paskyra sustabdyta.", - "empty_column.account_timeline": "Nėra įrašų čia.", + "empty_column.account_suspended": "Paskyra pristabdyta.", + "empty_column.account_timeline": "Nėra čia įrašų.", "empty_column.account_unavailable": "Profilis neprieinamas.", "empty_column.blocks": "Dar neužblokavai nė vieno naudotojo.", - "empty_column.bookmarked_statuses": "Dar neturi nė vienos įrašo žymės. Kai vieną iš jų pridėsi į žymes, jis bus rodomas čia.", - "empty_column.community": "Vietinė laiko skalė tuščia. Parašyk ką nors viešai, kad pradėtum bendrauti!", + "empty_column.bookmarked_statuses": "Dar neturi nė vienos įrašo pridėtos žymės. Kai vieną iš jų pridėsi į žymes, jis bus rodomas čia.", + "empty_column.community": "Vietinė laiko skalė yra tuščia. Parašyk ką nors viešai, kad pradėtum sąveikauti.", "empty_column.direct": "Dar neturi jokių privačių paminėjimų. Kai išsiųsi arba gausi vieną iš jų, jis bus rodomas čia.", "empty_column.domain_blocks": "Dar nėra užblokuotų domenų.", "empty_column.explore_statuses": "Šiuo metu niekas nėra tendencinga. Patikrink vėliau.", @@ -248,12 +262,13 @@ "empty_column.follow_requests": "Dar neturi jokių sekimo prašymų. Kai gausi tokį prašymą, jis bus rodomas čia.", "empty_column.followed_tags": "Dar neseki jokių saitažodžių. Kai tai padarysi, jie bus rodomi čia.", "empty_column.hashtag": "Nėra nieko šiame saitažodyje kol kas.", - "empty_column.home": "Tavo pagrindinio laiko skalė tuščia! Sek daugiau žmonių, kad ją užpildytum.", + "empty_column.home": "Tavo pagrindinio laiko skalė tuščia. Sek daugiau žmonių, kad ją užpildytum.", "empty_column.list": "Nėra nieko šiame sąraše kol kas. Kai šio sąrašo nariai paskelbs naujų įrašų, jie bus rodomi čia.", "empty_column.lists": "Dar neturi jokių sąrašų. Kai jį sukursi, jis bus rodomas čia.", "empty_column.mutes": "Dar nesi nutildęs (-usi) nė vieno naudotojo.", - "empty_column.notifications": "Dar neturi jokių pranešimų. Kai kiti žmonės su tavimi bendraus, matysi tai čia.", - "empty_column.public": "Čia nieko nėra! Parašyk ką nors viešai arba rankiniu būdu sek naudotojus iš kitų serverių, kad jį užpildytum.", + "empty_column.notification_requests": "Viskas švaru! Čia nieko nėra. Kai gausi naujų pranešimų, jie bus rodomi čia pagal tavo nustatymus.", + "empty_column.notifications": "Dar neturi jokių pranešimų. Kai kiti žmonės su tavimi sąveikaus, matysi tai čia.", + "empty_column.public": "Čia nieko nėra. Parašyk ką nors viešai arba rankiniu būdu sek naudotojus iš kitų serverių, kad jį užpildytum.", "error.unexpected_crash.explanation": "Dėl mūsų kodo riktos arba naršyklės suderinamumo problemos šis puslapis negalėjo būti rodomas teisingai.", "error.unexpected_crash.explanation_addons": "Šį puslapį nepavyko parodyti teisingai. Šią klaidą greičiausiai sukėlė naršyklės priedas arba automatinio vertimo įrankiai.", "error.unexpected_crash.next_steps": "Pabandyk atnaujinti puslapį. Jei tai nepadeda, galbūt vis dar galėsi naudotis Mastodon per kitą naršyklę arba savąją programėlę.", @@ -270,9 +285,9 @@ "filter_modal.added.context_mismatch_title": "Konteksto neatitikimas.", "filter_modal.added.expired_explanation": "Ši filtro kategorija nustojo galioti. Kad ji būtų taikoma, turėsi pakeisti galiojimo datą.", "filter_modal.added.expired_title": "Baigėsi filtro galiojimas.", - "filter_modal.added.review_and_configure": "Norint peržiūrėti ir toliau konfigūruoti šią filtro kategoriją, eik į nuorodą {settings_link}.", + "filter_modal.added.review_and_configure": "Norint peržiūrėti ir toliau konfigūruoti šią filtro kategoriją, eik į {settings_link}.", "filter_modal.added.review_and_configure_title": "Filtro nustatymai", - "filter_modal.added.settings_link": "nustatymų puslapis", + "filter_modal.added.settings_link": "nustatymų puslapį", "filter_modal.added.short_explanation": "Šis įrašas buvo pridėtas į šią filtro kategoriją: {title}.", "filter_modal.added.title": "Pridėtas filtras.", "filter_modal.select_filter.context_mismatch": "netaikoma šiame kontekste.", @@ -283,6 +298,8 @@ "filter_modal.select_filter.title": "Filtruoti šį įrašą", "filter_modal.title.status": "Filtruoti įrašą", "filtered_notifications_banner.mentions": "{count, plural, one {paminėjimas} few {paminėjimai} many {paminėjimo} other {paminėjimų}}", + "filtered_notifications_banner.pending_requests": "Pranešimai iš {count, plural, =0 {nė vieno} one {vienos žmogaus} few {# žmonių} many {# žmonių} other {# žmonių}}, kuriuos galbūt pažįsti", + "filtered_notifications_banner.title": "Filtruojami pranešimai", "firehose.all": "Visi", "firehose.local": "Šis serveris", "firehose.remote": "Kiti serveriai", @@ -295,8 +312,8 @@ "follow_suggestions.friends_of_friends_longer": "Populiarus tarp žmonių, kurių seki", "follow_suggestions.hints.featured": "Šį profilį atrinko {domain} komanda.", "follow_suggestions.hints.friends_of_friends": "Šis profilis yra populiarus tarp žmonių, kuriuos seki.", - "follow_suggestions.hints.most_followed": "Šis profilis yra vienas iš labiausiai sekamų {domain}.", - "follow_suggestions.hints.most_interactions": "Pastaruoju metu šis profilis sulaukia daug dėmesio šiame {domain}.", + "follow_suggestions.hints.most_followed": "Šis profilis yra vienas iš labiausiai sekamų domene {domain}.", + "follow_suggestions.hints.most_interactions": "Pastaruoju metu šis profilis sulaukia daug dėmesio domane {domain}.", "follow_suggestions.hints.similar_to_recently_followed": "Šis profilis panašus į profilius, kuriuos neseniai sekei.", "follow_suggestions.personalized_suggestion": "Suasmenintas pasiūlymas", "follow_suggestions.popular_suggestion": "Populiarus pasiūlymas", @@ -312,8 +329,8 @@ "footer.keyboard_shortcuts": "Spartieji klavišai", "footer.privacy_policy": "Privatumo politika", "footer.source_code": "Peržiūrėti šaltinio kodą", - "footer.status": "Būsena", - "generic.saved": "Išsaugoti", + "footer.status": "Statusas", + "generic.saved": "Išsaugota", "getting_started.heading": "Kaip pradėti", "hashtag.column_header.tag_mode.all": "ir {additional}", "hashtag.column_header.tag_mode.any": "ar {additional}", @@ -333,7 +350,7 @@ "home.column_settings.show_reblogs": "Rodyti pakėlimus", "home.column_settings.show_replies": "Rodyti atsakymus", "home.hide_announcements": "Slėpti skelbimus", - "home.pending_critical_update.body": "Kuo greičiau atnaujink savo Mastodon serverį!", + "home.pending_critical_update.body": "Kuo greičiau atnaujink savo Mastodon serverį.", "home.pending_critical_update.link": "Žiūrėti naujinimus", "home.pending_critical_update.title": "Galimas kritinis saugumo naujinimas.", "home.show_announcements": "Rodyti skelbimus", @@ -480,7 +497,7 @@ "notifications.column_settings.follow_request": "Nauji sekimo prašymai:", "notifications.column_settings.mention": "Paminėjimai:", "notifications.column_settings.poll": "Balsavimo rezultatai:", - "notifications.column_settings.push": "Stumdomieji pranešimai", + "notifications.column_settings.push": "Tiesioginiai pranešimai", "notifications.column_settings.reblog": "Pakėlimai:", "notifications.column_settings.show": "Rodyti stulpelyje", "notifications.column_settings.sound": "Paleisti garsą", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 55ceb564b6..32ea6e47c4 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -8,7 +8,7 @@ "about.domain_blocks.silenced.title": "Ierobežotie", "about.domain_blocks.suspended.explanation": "Nekādi dati no šī servera netiks apstrādāti, uzglabāti vai apmainīti, padarot neiespējamu mijiedarbību vai saziņu ar lietotājiem no šī servera.", "about.domain_blocks.suspended.title": "Apturētie", - "about.not_available": "Šī informācija šajā serverī nav bijusi pieejama.", + "about.not_available": "Šī informācija nav padarīta pieejama šajā serverī.", "about.powered_by": "Decentralizētu sociālo tīklu nodrošina {mastodon}", "about.rules": "Servera noteikumi", "account.account_note_header": "Piezīme", @@ -89,6 +89,9 @@ "announcement.announcement": "Paziņojums", "attachments_list.unprocessed": "(neapstrādāti)", "audio.hide": "Slēpt audio", + "block_modal.remote_users_caveat": "Mēs vaicāsim serverim {domain} ņemt vērā Tavu lēmumu. Tomēr atbilstība nav nodrošināta, jo atsevišķi serveri var apstrādāt bloķēšanu citādi. Publiski ieraksti joprojām var būt redzami lietotājiem, kuri nav pieteikušies.", + "block_modal.show_less": "Parādīt vairāk", + "block_modal.show_more": "Parādīt mazāk", "boost_modal.combo": "Nospied {combo}, lai nākamreiz šo izlaistu", "bundle_column_error.copy_stacktrace": "Kopēt kļūdu ziņojumu", "bundle_column_error.error.body": "Pieprasīto lapu nevarēja atveidot. Tas varētu būt saistīts ar kļūdu mūsu kodā, vai tā ir pārlūkprogrammas saderības problēma.", @@ -190,7 +193,7 @@ "directory.federated": "No pazīstamas federācijas", "directory.local": "Tikai no {domain}", "directory.new_arrivals": "Jaunpienācēji", - "directory.recently_active": "Nesen aktīvie", + "directory.recently_active": "Nesen aktīvi", "disabled_account_banner.account_settings": "Konta iestatījumi", "disabled_account_banner.text": "Tavs konts {disabledAccount} pašlaik ir atspējots.", "dismissable_banner.community_timeline": "Šie ir jaunākie publiskie ieraksti no cilvēkiem, kuru konti ir mitināti {domain}.", @@ -199,6 +202,9 @@ "dismissable_banner.explore_statuses": "Šie ir ieraksti, kas šodien gūst arvien lielāku ievērību visā sociālajā tīklā. Augstāk tiek kārtoti jaunāki ieraksti, kuri tiek vairāk pastiprināti un ievietoti izlasēs.", "dismissable_banner.explore_tags": "Šie tēmturi šobrīd kļūst arvien populārāki cilvēku vidū šajā un citos decentralizētā tīkla serveros.", "dismissable_banner.public_timeline": "Šie ir jaunākie publiskie ieraksti no lietotājiem sociālajā tīmeklī, kuriem {domain} seko cilvēki.", + "domain_block_modal.they_cant_follow": "Neviens šajā serverī nevar Tev sekot.", + "domain_pill.server": "Serveris", + "domain_pill.username": "Lietotājvārds", "embed.instructions": "Iestrādā šo ziņu savā mājaslapā, kopējot zemāk redzamo kodu.", "embed.preview": "Tas izskatīsies šādi:", "emoji_button.activity": "Aktivitāte", @@ -275,6 +281,7 @@ "follow_suggestions.curated_suggestion": "Darbinieku izvēle", "follow_suggestions.dismiss": "Vairs nerādīt", "follow_suggestions.personalized_suggestion": "Pielāgots ieteikums", + "follow_suggestions.similar_to_recently_followed_longer": "Līdzīgi profieliem, kuriem nesen sāki sekot", "follow_suggestions.view_all": "Skatīt visu", "follow_suggestions.who_to_follow": "Kam sekot", "followed_tags": "Sekojamie tēmturi", @@ -388,6 +395,10 @@ "loading_indicator.label": "Ielādē…", "media_gallery.toggle_visible": "{number, plural, one {Slēpt attēlu} other {Slēpt attēlus}}", "moved_to_account_banner.text": "Tavs konts {disabledAccount} pašlaik ir atspējots, jo Tu pārcēlies uz kontu {movedToAccount}.", + "mute_modal.hide_from_notifications": "Paslēpt paziņojumos", + "mute_modal.hide_options": "Paslēpt iespējas", + "mute_modal.show_options": "Parādīt iespējas", + "mute_modal.title": "Apklusināt lietotāju?", "navigation_bar.about": "Par", "navigation_bar.advanced_interface": "Atvērt paplašinātā tīmekļa saskarnē", "navigation_bar.blocks": "Bloķētie lietotāji", @@ -420,11 +431,23 @@ "notification.follow": "{name} uzsāka Tev sekot", "notification.follow_request": "{name} nosūtīja Tev sekošanas pieprasījumu", "notification.mention": "{name} pieminēja Tevi", + "notification.moderation-warning.learn_more": "Uzzināt vairāk", + "notification.moderation_warning.action_delete_statuses": "Daži no Taviem ierakstiem tika noņemti.", + "notification.moderation_warning.action_disable": "Tavs konts tika atspējots.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Daži no Taviem ierakstiem tika atzīmēti kā jutīgi.", + "notification.moderation_warning.action_sensitive": "Tavi ieraksti turpmāk tiks atzīmēti kā jutīgi.", + "notification.moderation_warning.action_silence": "Tavs konts tika ierobežots.", + "notification.moderation_warning.action_suspend": "Tava konta darbība tika apturēta.", "notification.own_poll": "Tava aptauja ir noslēgusies", "notification.poll": "Aptauja, kurā tu piedalījies, ir noslēgusies", "notification.reblog": "{name} pastiprināja Tavu ierakstu", + "notification.relationships_severance_event": "Zaudēti savienojumi ar {name}", + "notification.relationships_severance_event.learn_more": "Uzzināt vairāk", "notification.status": "{name} tikko publicēja", "notification.update": "{name} rediģēja ierakstu", + "notification_requests.accept": "Pieņemt", + "notification_requests.dismiss": "Noraidīt", + "notification_requests.notifications_from": "Paziņojumi no {name}", "notifications.clear": "Notīrīt paziņojumus", "notifications.clear_confirmation": "Vai tiešām vēlies neatgriezeniski notīrīt visus savus paziņojumus?", "notifications.column_settings.admin.report": "Jauni ziņojumi:", @@ -456,6 +479,9 @@ "notifications.permission_denied": "Darbvirsmas paziņojumi nav pieejami, jo iepriekš tika noraidīts pārlūka atļauju pieprasījums", "notifications.permission_denied_alert": "Darbvirsmas paziņojumus nevar iespējot, jo pārlūkprogrammai atļauja tika iepriekš atteikta", "notifications.permission_required": "Darbvirsmas paziņojumi nav pieejami, jo nav piešķirta nepieciešamā atļauja.", + "notifications.policy.filter_new_accounts_title": "Jauni konti", + "notifications.policy.filter_not_followers_title": "Cilvēki, kuri Tev neseko", + "notifications.policy.filter_not_following_title": "Cilvēki, kuriem Tu neseko", "notifications_permission_banner.enable": "Iespējot darbvirsmas paziņojumus", "notifications_permission_banner.how_to_control": "Lai saņemtu paziņojumus, kad Mastodon nav atvērts, iespējo darbvirsmas paziņojumus. Vari precīzi kontrolēt, kāda veida mijiedarbības rada darbvirsmas paziņojumus, izmantojot augstāk redzamo pogu {icon}, kad tie būs iespējoti.", "notifications_permission_banner.title": "Nekad nepalaid neko garām", @@ -485,7 +511,7 @@ "onboarding.start.title": "Tev tas izdevās!", "onboarding.steps.follow_people.body": "Tu pats veido savu plūsmu. Piepildīsim to ar interesantiem cilvēkiem.", "onboarding.steps.follow_people.title": "Pielāgo savu mājas barotni", - "onboarding.steps.publish_status.body": "Sveicini pasauli ar tekstu, fotoattēliem, video, vai aptaujām {emoji}", + "onboarding.steps.publish_status.body": "Pasveicini pasauli ar tekstu, attēliem, video vai aptaujām {emoji}", "onboarding.steps.publish_status.title": "Izveido savu pirmo ziņu", "onboarding.steps.setup_profile.body": "Palielini mijiedarbību ar aptverošu profilu!", "onboarding.steps.setup_profile.title": "Pielāgo savu profilu", @@ -603,7 +629,7 @@ "search_results.statuses": "Ieraksti", "search_results.title": "Meklēt {q}", "server_banner.about_active_users": "Cilvēki, kas izmantojuši šo serveri pēdējo 30 dienu laikā (aktīvie lietotāji mēnesī)", - "server_banner.active_users": "aktīvie lietotāji", + "server_banner.active_users": "aktīvi lietotāji", "server_banner.administered_by": "Administrē:", "server_banner.introduction": "{domain} ir daļa no decentralizētā sociālā tīkla, ko nodrošina {mastodon}.", "server_banner.learn_more": "Uzzināt vairāk", @@ -625,6 +651,7 @@ "status.direct": "Pieminēt @{name} privāti", "status.direct_indicator": "Pieminēts privāti", "status.edit": "Labot", + "status.edited": "Pēdējoreiz labots {date}", "status.edited_x_times": "Labots {count, plural, one {{count} reizi} other {{count} reizes}}", "status.embed": "Iegult", "status.favourite": "Izlasē", diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index b365668210..d83c708647 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -21,28 +21,47 @@ ia: confirmation_instructions: action: Verificar adresse de e-mail action_with_app: Confirmar e retornar a %{app} + explanation: Tu ha create un conto sur %{host} con iste adresse de e-mail. Tu es a un sol clic de activar lo. Si isto non esseva tu, per favor ignora iste e-mail. + explanation_when_pending: Tu ha sollicitate un invitation a %{host} con iste adresse de e-mail. Post que tu confirma tu adresse de e-mail, nos va revider tu demanda. Tu pote aperir session pro cambiar tu detalios o eliminar tu conto, ma tu non pote acceder al majoritate del functiones usque tu conto es approbate. Si tu demanda es rejectate, tu datos essera removite e nulle action ulterior essera requirite de te. Si isto non esseva tu, per favor ignora iste message de e-mail. + extra_html: Per favor consulta tamben le regulas del servitor e nostre conditiones de servicio. subject: 'Mastodon: Instructiones de confirmation pro %{instance}' title: Verificar adresse de e-mail email_changed: explanation: 'Le adresse de e-mail pro tu conto essera cambiate a:' + extra: Si tu non ha cambiate de adresse de e-mail, es probabile que alcuno ha ganiate le accesso a tu conto. Per favor cambia immediatemente tu contrasigno o contacta le administrator del servitor si tu non pote acceder a tu conto. subject: 'Mastodon: E-mail cambiate' title: Nove adresse de e-mail password_change: explanation: Le contrasigno de tu conto ha essite cambiate. + extra: Si tu non ha cambiate tu contrasigno, es probabile que alcuno ha ganiate le accesso a tu conto. Per favor cambia immediatemente tu contrasigno o contacta le administrator del servitor si tu non pote acceder a tu conto. subject: 'Mastodon: Contrasigno cambiate' title: Contrasigno cambiate reconfirmation_instructions: explanation: Confirma le nove adresse pro cambiar tu email. + extra: Si non es tu qui ha initiate iste cambiamento, per favor ignora iste e-mail. Le adresse de e-mail pro le conto de Mastodon non cambiara usque tu accede al ligamine hic supra. subject: 'Mastodon: Confirmar e-mail pro %{instance}' title: Verificar adresse de e-mail reset_password_instructions: action: Cambiar contrasigno + explanation: Tu ha requestate un nove contrasigno pro tu conto. + extra: Si tu non ha requestate isto, per favor ignora iste e-mail. Tu contrasigno non cambiara usque tu accede al ligamine hic supra e crea un nove. subject: 'Mastodon: Instructiones pro reinitialisar le contrasigno' title: Reinitialisar contrasigno two_factor_disabled: + explanation: Ora es possibile aperir session con solmente le adresse de e-mail e contrasigno. + subject: 'Mastodon: Authentication bifactorial disactivate' + subtitle: Le authentication bifactorial ha essite disactivate pro tu conto. title: 2FA disactivate two_factor_enabled: + explanation: Pro le apertura de session essera necessari un token generate per le application TOTP accopulate. + subject: 'Mastodon: Authentication bifactorial activate' + subtitle: Le authentication bifactorial ha essite activate pro tu conto. title: 2FA activate + two_factor_recovery_codes_changed: + explanation: Le ancian codices de recuperation ha essite invalidate e nove codices ha essite generate. + subject: 'Mastodon: Codices de recuperation regenerate' + subtitle: Le ancian codices de recuperation ha essite invalidate e nove codices ha essite generate. + title: Codices de recuperation cambiate unlock_instructions: subject: 'Mastodon: Instructiones pro disblocar' webauthn_credential: @@ -53,9 +72,15 @@ ia: deleted: explanation: Le sequente clave de securitate esseva delite de tu conto subject: 'Mastodon: Clave de securitate delite' + title: Un de tu claves de securitate ha essite delite webauthn_disabled: + explanation: Le authentication con claves de securitate ha essite disactivate pro tu conto. + extra: Ora es possibile aperir session usante solmente le token generate per le application TOTP accopulate. + subject: 'Mastodon: Le authentication con claves de securitate es disactivate' title: Claves de securitate disactivate webauthn_enabled: + explanation: Le authentication con claves de securitate ha essite activate pro tu conto. + extra: Tu clave de securitate pote ora esser usate pro aperir session. title: Claves de securitate activate registrations: destroyed: A revider! Tu conto esseva cancellate con successo. Nos spera vider te novemente tosto. diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index 86bd1ad985..b5bd6cc536 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -34,10 +34,12 @@ ia: title: Nove application show: actions: Actiones + scopes: Ambitos title: 'Application: %{name}' authorizations: buttons: authorize: Autorisar + deny: Negar error: title: Ocurreva un error authorized_applications: @@ -66,7 +68,9 @@ ia: conversations: Conversationes favourites: Favoritos filters: Filtros + follows: Sequites lists: Listas + media: Annexos multimedial mutes: Silentiates notifications: Notificationes push: Notificationes push diff --git a/config/locales/doorkeeper.ie.yml b/config/locales/doorkeeper.ie.yml index 0119f3573f..fc8132c926 100644 --- a/config/locales/doorkeeper.ie.yml +++ b/config/locales/doorkeeper.ie.yml @@ -174,6 +174,7 @@ ie: read:filters: vider tui filtres read:follows: vider tui sequitores read:lists: vider tui listes + read:me: leer solmen li basic information de tui conto read:mutes: vider tui silentias read:notifications: vider tui notificationes read:reports: vider tui raportes diff --git a/config/locales/doorkeeper.lt.yml b/config/locales/doorkeeper.lt.yml index 5be291bf89..82695d8ba6 100644 --- a/config/locales/doorkeeper.lt.yml +++ b/config/locales/doorkeeper.lt.yml @@ -31,8 +31,8 @@ lt: form: error: Ups! Patikrink, ar formoje nėra galimų klaidų. help: - native_redirect_uri: Naudoti %{native_redirect_uri} vietiniams bandymams - redirect_uri: Naudoti po vieną eilutę kiekvienam URI + native_redirect_uri: Naudok %{native_redirect_uri} vietiniams bandymams. + redirect_uri: Naudok po vieną eilutę kiekvienam URI. scopes: Atskirk aprėptis tarpais. Palik tuščią, jei nori naudoti numatytąsias aprėtis. index: application: Programėlė @@ -90,7 +90,7 @@ lt: request_not_authorized: Užklausą reikia įgalioti. Reikalingo parametro užklausai įgalioti trūksta arba jis netinkamas. unknown: Užklausoje trūksta privalomo parametro, turi nepalaikomą parametro reikšmę arba yra kitaip netinkamai suformuota. invalid_resource_owner: Pateikti išteklių savininko įgaliojimai yra netinkami arba išteklių savininko negalima surasti. - invalid_scope: Užklausos aprėptis yra netinkama, nežinoma arba netinkamai suformuota. + invalid_scope: Užklausos aprėptis yra netinkama, nežinoma arba netaisyklingas. invalid_token: expired: Baigėsi prieigos rakto galiojimas. revoked: Prieigos raktas buvo panaikintas. @@ -133,9 +133,9 @@ lt: follows: Sekimai lists: Sąrašai media: Medijos priedai - mutes: Užtildymai + mutes: Nutildymai notifications: Pranešimai - push: Stumdomieji pranešimai + push: Tiesioginiai pranešimai reports: Ataskaitos search: Paieška statuses: Įrašai @@ -147,30 +147,30 @@ lt: application: title: Reikalingas OAuth leidimas scopes: - admin:read: skaityti visus serveryje esančius duomenis - admin:read:accounts: skaityti neskelbtiną visų paskyrų informaciją - admin:read:canonical_email_blocks: skaityti neskelbtiną visų kanoninių el. laiško blokavimų informaciją - admin:read:domain_allows: skaityti neskelbtiną visų domeno leidimus informaciją - admin:read:domain_blocks: skaityti neskelbtiną visų domeno blokavimų informaciją - admin:read:email_domain_blocks: skaityti neskelbtiną visų el. laiško domeno blokavimų informaciją - admin:read:ip_blocks: skaityti neskelbtiną visų IP blokavimų informaciją - admin:read:reports: skaityti neskelbtiną visų ataskaitų ir praneštų paskyrų informaciją - admin:write: modifikuoti visus serveryje esančius duomenis + admin:read: skaityti visus duomenis serveryje + admin:read:accounts: skaityti slaptą visų paskyrų informaciją + admin:read:canonical_email_blocks: skaityti slaptą visų kanoninių el. laiško blokavimų informaciją + admin:read:domain_allows: skaityti slaptą visų domeno leidimus informaciją + admin:read:domain_blocks: skaityti slaptą visų domeno blokavimų informaciją + admin:read:email_domain_blocks: skaityti slaptą visų el. laiško domeno blokavimų informaciją + admin:read:ip_blocks: skaityti slaptą visų IP blokavimų informaciją + admin:read:reports: skaityti slaptą visų ataskaitų ir praneštų paskyrų informaciją + admin:write: modifikuoti visus duomenis serveryje admin:write:accounts: atlikti paskyrų prižiūrėjimo veiksmus admin:write:canonical_email_blocks: atlikti kanoninių el. laiško blokavimų prižiūrėjimo veiksmus - admin:write:domain_allows: atlikti prižiūrėjimo veiksmus su domeno leidimais - admin:write:domain_blocks: atlikti prižiūrėjimo veiksmus su domenų blokavimais - admin:write:email_domain_blocks: atlikti prižiūrėjimo veiksmus su el. laiško domenų blokavimais - admin:write:ip_blocks: atlikti prižiūrėjimo veiksmus su IP blokavimais - admin:write:reports: atlikti paskyrų prižiūrėjimo veiksmus atsakaitams + admin:write:domain_allows: atlikti domeno leidimų prižiūrėjimo veiksmus + admin:write:domain_blocks: atlikti domeno blokavimų prižiūrėjimo veiksmus + admin:write:email_domain_blocks: atlikti el. laiško domenų blokavimų prižiūrėjimo veiksmus + admin:write:ip_blocks: atlikti IP blokavimų prižiūrėjimo veiksmus + admin:write:reports: atlikti ataskaitų prižiūrėjimo veiksmus crypto: naudoti visapusį šifravimą follow: modifikuoti paskyros sąryšius - push: gauti tavo stumiamuosius pranešimus - read: skaityti tavo visus paskyros duomenis + push: gauti tiesioginius pranešimus + read: skaityti visus paskyros duomenis read:accounts: matyti paskyrų informaciją read:blocks: matyti tavo blokavimus read:bookmarks: matyti tavo žymes - read:favourites: matyti tavo mėgstamiausius + read:favourites: matyti tavo mėgstamus read:filters: matyti tavo filtrus read:follows: matyti tavo sekimus read:lists: matyti tavo sąrašus @@ -183,14 +183,14 @@ lt: write: modifikuoti visus tavo paskyros duomenis write:accounts: modifikuoti tavo profilį write:blocks: blokuoti paskyras ir domenus - write:bookmarks: įrašyti įrašus + write:bookmarks: pridėti į žymes įrašus write:conversations: nutildyti ir ištrinti pokalbius - write:favourites: mėgti įrašai + write:favourites: pamėgti įrašus write:filters: sukurti filtrus write:follows: sekti žmones write:lists: sukurti sąrašus write:media: įkelti medijos failus write:mutes: nutildyti žmones ir pokalbius write:notifications: išvalyti tavo pranešimus - write:reports: pranešti kitus asmenus + write:reports: pranešti apie kitus žmones write:statuses: skelbti įrašus diff --git a/config/locales/gl.yml b/config/locales/gl.yml index bdf6e5a75f..57af7c82c0 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -5,7 +5,7 @@ gl: contact_missing: Non establecido contact_unavailable: Non dispoñíbel hosted_on: Mastodon aloxado en %{domain} - title: Acerca de + title: Sobre accounts: follow: Seguir followers: @@ -503,7 +503,7 @@ gl: instance_follows_measure: as súas seguidoras aquí instance_languages_dimension: Top de idiomas instance_media_attachments_measure: anexos multimedia gardados - instance_reports_measure: denuncias acerca deles + instance_reports_measure: denuncias sobre eles instance_statuses_measure: publicacións gardadas delivery: all: Todo @@ -615,7 +615,7 @@ gl: created_at: Denunciado delete_and_resolve: Eliminar publicacións forwarded: Reenviado - forwarded_replies_explanation: Esta denuncia procede dunha usuaria remota e acerca de contido remoto. Enviouseche unha copia porque o contido denunciado é unha resposta a unha das túas usuarias. + forwarded_replies_explanation: Esta denuncia procede dunha usuaria remota e sobre contido remoto. Enviouseche unha copia porque o contido denunciado é unha resposta a unha das túas usuarias. forwarded_to: Reenviado a %{domain} mark_as_resolved: Marcar como resolto mark_as_sensitive: Marcar como sensible @@ -740,7 +740,7 @@ gl: manage_rules: Xestionar regras do servidor preamble: Proporciona información detallada acerca do xeito en que se xestiona, modera e financia o servidor. rules_hint: Hai un espazo dedicado para as normas que é de agardar as usuarias acaten. - title: Acerca de + title: Sobre appearance: preamble: Personalizar a interface web de Mastodon. title: Aparencia @@ -1870,7 +1870,7 @@ gl: feature_action: Saber máis feature_audience: Mastodon dache a oportunidade de xestionar sen intermediarios as túas relacións. Incluso se usas o teu propio servidor Mastodon poderás seguir e ser seguida desde calquera outro servidor Mastodon conectado á rede e estará baixo o teu control exclusivo. feature_audience_title: Crea a túa audiencia con tranquilidade - feature_control: Sabes mellor ca ninguén o que queres ver na cronoloxía. Non hai algoritmos nin publicidade facéndoche perder o tempo. Segue cunha soa conta a outras persoas en servidores Mastodon diferentes ao teu, recibirás as publicacións en orde cronolóxica, e farás deste curruchiño de internet un lugar para ti. + feature_control: Sabes mellor ca ninguén o que queres ver na cronoloxía. Non hai algoritmos nin publicidade facéndoche perder o tempo. Sigue cunha soa conta a outras persoas en servidores Mastodon diferentes ao teu, recibirás as publicacións en orde cronolóxica, e farás deste curruchiño de internet un lugar para ti. feature_control_title: Tes o control da túa cronoloxía feature_creativity: Mastodon ten soporte para audio, vídeo e imaxes nas publicacións, descricións para mellorar a accesibilidade, enquisas, avisos sobre o contido, avatares animados, emojis personalizados, control sobre o recorte de miniaturas, e moito máis, para axudarche a expresarte en internet. Tanto se publicas o teu arte, música ou podcast, Mastodon está aquí para ti. feature_creativity_title: Creatividade incomparable diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 193f2b0d59..712328deb8 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -886,6 +886,7 @@ ia: one: Compartite per un persona le septimana passate other: Compartite per %{count} personas le septimana passate title: Ligamines de tendentia + usage_comparison: Compartite %{today} vices hodie, comparate al %{yesterday} de heri not_allowed_to_trend: Non permittite haber tendentia only_allowed: Solo permittite pending_review: Attende revision @@ -915,6 +916,7 @@ ia: tag_servers_dimension: Servitores principal tag_servers_measure: servitores differente tag_uses_measure: usos total + description_html: Istos es hashtags que actualmente appare in tante messages que tu servitor vide. Illo pote adjutar tu usatores a discoperir re que le personas parla plus al momento. Nulle hashtags es monstrate publicamente usque tu los approba. listable: Pote esser suggerite no_tag_selected: Nulle placas era cambiate perque nulle era seligite not_listable: Non sera suggerite @@ -940,21 +942,47 @@ ia: webhooks: add_new: Adder terminal delete: Deler + description_html: Un croc web habilita Mastodon a transmitter notificationes in tempore real re eventos seligite pro tu pro activar application, assi tu application pote automaticamente discatenar reactiones. disable: Disactivar disabled: Disactivate edit: Rediger terminal + empty: Tu ancora non ha configurate alcun punctos final de web croc. enable: Activar enabled: Active enabled_events: one: 1 evento activate other: "%{count} eventos activate" events: Eventos + new: Nove croc web + rotate_secret: Rotar secrete + secret: Firmante secrete status: Stato + title: Crocs web + webhook: Crocs web admin_mailer: + auto_close_registrations: + subject: Le registrationes pro %{instance} ha essite automaticamente mutate a besoniante de approbation + new_appeal: + actions: + delete_statuses: pro deler lor messages + disable: pro gelar lor conto + mark_statuses_as_sensitive: pro marcar lor messages como sensibile + none: pro advertir + sensitive: a marcar lor conto como sensibile + silence: pro limitar lor conto + suspend: pro suspender lor conto + body: "%{target} appella un decision de moderation per %{action_taken_by} ab le %{date}, que era %{type}. Ille scribeva:" new_critical_software_updates: subject: Actualisationes critic de Mastodon es disponibile pro %{instance}! new_software_updates: subject: Nove versiones de Mastodon es disponibile pro %{instance}! + new_trends: + new_trending_links: + title: Ligamines de tendentia + new_trending_statuses: + title: Messages de tendentia + new_trending_tags: + title: Hashtags de tendentia aliases: add_new: Crear alias appearance: @@ -962,6 +990,7 @@ ia: confirmation_dialogs: Dialogos de confirmation discovery: Discoperta localization: + body: Mastodon es traducite per voluntarios. guide_link: https://crowdin.com/project/mastodon guide_link_text: Totes pote contribuer. sensitive_content: Contento sensibile @@ -1026,8 +1055,16 @@ ia: account_status: Stato del conto view_strikes: Examinar le admonitiones passate contra tu conto challenge: + confirm: Continuar invalid_password: Contrasigno non valide prompt: Confirma le contrasigno pro continuar + datetime: + distance_in_words: + half_a_minute: Justo ora + less_than_x_seconds: Justo ora + over_x_years: "%{count}a" + x_days: "%{count}d" + x_minutes: "%{count} m" deletes: confirm_password: Insere tu contrasigno actual pro verificar tu identitate proceed: Deler le conto @@ -1206,6 +1243,10 @@ ia: activity: Activitate del conto most_recent: Plus recente status: Stato del conto + rss: + content_warning: 'Advertimento de contento:' + descriptions: + account: Messages public de @%{acct} sessions: activity: Ultime activitate browser: Navigator @@ -1253,6 +1294,7 @@ ia: delete: Deletion de conto development: Disveloppamento edit_profile: Modificar profilo + featured_tags: Hashtags eminente import: Importar migrate: Migration de conto notifications: Notificationes de e-mail @@ -1261,7 +1303,9 @@ ia: relationships: Sequites e sequitores strikes: Admonitiones de moderation severed_relationships: + download: Discargar (%{count}) event_type: + account_suspension: Suspension del conto (%{target_name}) domain_block: Suspension del servitor (%{target_name}) user_domain_block: Tu ha blocate %{target_name} preamble: Tu pote perder sequites e sequitores quando tu bloca un dominio o quando tu moderatores decide suspender un servitor remote. Quando isto occurre, tu potera discargar listas de relationes rumpite, a inspectar e eventualmente importar in un altere servitor. diff --git a/config/locales/ie.yml b/config/locales/ie.yml index 46e55b9e19..2b819c53de 100644 --- a/config/locales/ie.yml +++ b/config/locales/ie.yml @@ -1667,8 +1667,10 @@ ie: download: Descargar (%{count}) event_type: account_suspension: Suspension del conto (%{target_name}) + domain_block: Suspension del servitor (%{target_name}) user_domain_block: Tu bloccat %{target_name} lost_followers: Perdit sequitores + lost_follows: Perdit sequetes preamble: Tu posse perdir tis queles tu seque e tui sequitores quande tu blocca un domonia o quande tui moderatores decide suspender un lontan servitor. Tande, tu va posser descargar listes de dejuntet relationes, a inspecter e possibilmen importar sur un altri servitor. type: Eveniment statuses: diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 0e90cc723e..f3f3e3a8fb 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -739,6 +739,7 @@ ko: desc_html: 이것은 hCaptcha의 외부 스크립트에 의존합니다, 이것은 개인정보 보호에 위협을 가할 수도 있습니다. 추가적으로, 이것은 몇몇 사람들(특히나 장애인들)에게 가입 절차의 접근성을 심각하게 떨어트릴 수 있습니다. 이러한 이유로, 대체제로 승인 전용이나 초대제를 통한 가입을 고려해보세요. title: 새로운 사용자가 계정 확인을 위해서는 CAPTCHA를 풀어야 하도록 합니다 content_retention: + danger_zone: 위험한 영역 preamble: 마스토돈에 저장된 사용자 콘텐츠를 어떻게 다룰지 제어합니다. title: 콘텐츠 보존기한 default_noindex: diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 35111ad396..b815cada5c 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -535,12 +535,16 @@ lt: elasticsearch_preset_single_node: message_html: Tavo Elasticsearch klasteris turi tik vieną mazgą, ES_PRESET turėtų būti nustatyta į single_node_cluster. title: Administracija + trends: + preview_card_providers: + title: Leidėjai warning_presets: add_new: Pridėti naują delete: Ištrinti edit_preset: Keisti įspėjimo nustatymus title: Valdyti įspėjimo nustatymus webhooks: + description_html: "Webhook leidžia Mastodon siųsti realaus laiko pranešimus apie pasirinktus įvykius į tavo programą, kad programa galėtų automatiškai paleisti reakcijas." events: Įvykiai admin_mailer: auto_close_registrations: @@ -665,6 +669,7 @@ lt: invalid_context: Jokio arba netinkamas pateiktas kontekstas index: delete: Ištrinti + empty: Neturi jokių filtrų. title: Filtrai new: title: Pridėti naują filtrą diff --git a/config/locales/lv.yml b/config/locales/lv.yml index ee83954007..f4f0aa9db2 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -761,6 +761,7 @@ lv: desc_html: Tas balstās uz ārējiem skriptiem no hCaptcha, kas var radīt bažas par drošību un privātumu. Turklāt tas var padarīt reģistrācijas procesu ievērojami mazāk pieejamu dažiem cilvēkiem (īpaši invalīdiem). Šo iemeslu dēļ, lūdzu, apsver alternatīvus pasākumus, piemēram, reģistrāciju, kas balstīta uz apstiprinājumu vai uzaicinājumu. title: Pieprasīt jaunajiem lietotājiem atrisināt CAPTCHA, lai apstiprinātu savu kontu content_retention: + danger_zone: Bīstama sadaļa preamble: Kontrolē, kā Mastodon tiek glabāts lietotāju ģenerēts saturs. title: Satura saglabāšana default_noindex: @@ -1631,6 +1632,7 @@ lv: unknown_browser: Nezināms Pārlūks weibo: Weibo current_session: Pašreizējā sesija + date: Datums description: "%{browser} uz %{platform}" explanation: Šie ir tīmekļa pārlūki, kuros šobrīd esi pieteicies savā Mastodon kontā. ip: IP @@ -1667,6 +1669,7 @@ lv: import: Imports import_and_export: Imports un eksports migrate: Konta migrācija + notifications: E-pasta paziņojumi preferences: Iestatījumi profile: Profils relationships: Sekojamie un sekotāji @@ -1674,6 +1677,9 @@ lv: strikes: Moderācijas aizrādījumi two_factor_authentication: Divpakāpju autentifikācija webauthn_authentication: Drošības atslēgas + severed_relationships: + download: Lejupielādēt (%{count}) + type: Notikums statuses: attached: audio: @@ -1800,6 +1806,7 @@ lv: webauthn: Drošības atslēgas user_mailer: appeal_approved: + action: Konta iestatījumi explanation: Apelācija par brīdinājumu jūsu kontam %{strike_date}, ko iesniedzāt %{appeal_date}, ir apstiprināta. Jūsu konts atkal ir labā stāvoklī. subject: Jūsu %{date} apelācija ir apstiprināta title: Apelācija apstiprināta @@ -1849,15 +1856,28 @@ lv: silence: Konts ierobežots suspend: Konts apturēts welcome: + apps_android_action: Iegūt to Google Play + apps_title: Mastodon lietotnes edit_profile_action: Pielāgot edit_profile_title: Pielāgo savu profilu explanation: Šeit ir daži padomi, kā sākt darbu + feature_action: Uzzināt vairāk feature_creativity: Mastodon nodrošina skaņas, video un attēlu ierakstus, pieejamības aprakstus, aptaujas, satura brīdinājumus, animētus profila attēlus, pielāgotas emocijzīmes, sīktēlu apgriešanas vadīklas un vēl, lai palīdzētu Tev sevi izpaust tiešsaistē. Vai Tu izplati savu mākslu, mūziku vai aplādes, Mastodon ir šeit ar Tevi. + follow_action: Sekot follow_title: Pielāgo savu mājas barotni + follows_title: Kam sekot + follows_view_more: Rādīt vairāk cilvēku, kuriem sekot hashtags_recent_count: one: "%{people} cilvēks pēdējās 2 dienās" other: "%{people} cilvēki pēdējās 2 dienās" zero: "%{people} cilvēku pēdējās divās dienās" + post_action: Rakstīt + post_step: Pasveicini pasauli ar tekstu, fotoattēliem, video vai aptaujām! + post_title: Izveido savu pirmo ierakstu + share_action: Kopīgot + share_step: Dari saviem draugiem zināmu, kā Tevi atrast Mastodon! + share_title: Kopīgo savu Mastodon profilu + sign_in_action: Pieteikties subject: Laipni lūgts Mastodon title: Laipni lūgts uz borta, %{name}! users: @@ -1865,6 +1885,7 @@ lv: go_to_sso_account_settings: Dodies uz sava identitātes nodrošinātāja konta iestatījumiem invalid_otp_token: Nederīgs divfaktora kods otp_lost_help_html: Ja esi zaudējis piekļuvi abiem, tu vari sazināties ar %{email} + rate_limited: Pārāk daudz autentifikācijas mēģinājumu, vēlāk jāmēģina vēlreiz. seamless_external_login: Tu esi pieteicies, izmantojot ārēju pakalpojumu, tāpēc paroles un e-pasta iestatījumi nav pieejami. signed_in_as: 'Pieteicies kā:' verification: diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 9cb9cadee9..60730d53e9 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -751,6 +751,7 @@ pt-BR: desc_html: Isso é baseado em scripts externos de hCaptcha, o que pode ser uma preocupação de segurança e privacidade. Além disso, isso pode tornar o processo de registro significativamente menos acessível para algumas pessoas (especialmente deficientes). Por estas razões, favor considerar medidas alternativas como o registro baseado em aprovação ou em convite. title: Exigir que novos usuários resolvam um CAPTCHA para confirmar sua conta content_retention: + danger_zone: Zona de perigo preamble: Controlar como o conteúdo gerado pelo usuário é armazenado no Mastodon. title: Retenção de conteúdo default_noindex: diff --git a/config/locales/ro.yml b/config/locales/ro.yml index 1099e3d0d7..cd54d51051 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -566,6 +566,7 @@ ro: blocking: Lista de blocare domain_blocking: Listă de blocare domenii following: Lista de urmărire + lists: Liste muting: Lista de ignorare upload: Încarcă invites: @@ -622,6 +623,14 @@ ro: body: 'Postarea ta a fost impulsionată de %{name}:' subject: "%{name} ți-a impulsionat postarea" title: Impuls nou + number: + human: + decimal_units: + units: + billion: B + million: M + quadrillion: Q + thousand: K polls: errors: expired: Sondajul s-a încheiat deja diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml index a1406b1ad9..370667d48e 100644 --- a/config/locales/simple_form.ar.yml +++ b/config/locales/simple_form.ar.yml @@ -77,10 +77,15 @@ ar: warn: إخفاء المحتوى الذي تم تصفيته خلف تحذير يذكر عنوان الفلتر form_admin_settings: activity_api_enabled: عدد المنشورات المحلية و المستخدمين الناشطين و التسجيلات الأسبوعية الجديدة + app_icon: WEBP أو PNG أو GIF أو JPG. يتجاوز أيقونة التطبيق الافتراضية على الجوالات مع أيقونة مخصصة. + backups_retention_period: للمستخدمين القدرة على إنشاء أرشيفات لمنشوراتهم لتحميلها في وقت لاحق. عند التعيين إلى قيمة موجبة، سيتم حذف هذه الأرشيف تلقائياً من وحدة تخزينك بعد عدد الأيام المحدد. bootstrap_timeline_accounts: سيتم تثبيت هذه الحسابات على قمة التوصيات للمستخدمين الجدد. closed_registrations_message: ما سيعرض عند إغلاق التسجيلات + content_cache_retention_period: سيتم حذف جميع المنشورات من الخوادم الأخرى (بما في ذلك التعزيزات والردود) بعد عدد الأيام المحدد، دون أي تفاعل محلي للمستخدم مع هذه المنشورات. وهذا يشمل المنشورات التي قام المستخدم المحلي بوضع علامة عليها كإشارات مرجعية أو المفضلة. وسوف تختفي أيضا الإشارات الخاصة بين المستخدمين من المثيلات المختلفة ويستحيل استعادتها. والغرض من استخدام هذا الإعداد هو مثيلات الغرض الخاص ويفسد الكثير من توقعات المستخدمين عند تنفيذها للاستخدام لأغراض عامة. custom_css: يمكنك تطبيق أساليب مخصصة على نسخة الويب من ماستدون. + favicon: WEBP أو PNG أو GIF أو JPG. يتجاوز أيقونة التطبيق المفضلة الافتراضية مع أيقونة مخصصة. mascot: تجاوز الرسوم التوضيحية في واجهة الويب المتقدمة. + media_cache_retention_period: ملفات الوسائط من المنشورات التي يقوم بها المستخدمون البعيدون يتم تخزينها في خادمك. عند التعيين إلى قيمة موجبة، سيتم حذف الوسائط بعد عدد الأيام المحدد. إذا كانت بيانات الوسائط مطلوبة بعد حذفها، فسيتم إعادة تحميلها إذا كان محتوى المصدر لا يزال متاحًا. بسبب القيود المفروضة على عدد المرات التي يتم فيها ربط بطاقات المعاينة لمواقع الطرف الثالث، يوصى بتعيين هذه القيمة إلى 14 يوماً على الأقل، أو لن يتم تحديث بطاقات معاينة الرابط عند الطلب قبل ذلك الوقت. peers_api_enabled: قائمة بأسماء النطاقات التي صادفها هذا الخادم في الفدرالية. لا توجد بيانات هنا حول ما إذا كنت تتحد مع خادم معين، فقط أن خادمك يعرف عنها. ويستخدم هذا الخدمات التي تجمع الإحصاءات المتعلقة بالاتحاد بشكل عام. profile_directory: دليل الملف الشخصي يسرد جميع المستخدمين الذين اختاروا الدخول ليكونوا قابلين للاكتشاف. require_invite_text: عندما تتطلب التسجيلات الموافقة اليدوية، اجعل إدخال النص "لماذا تريد الانضمام ؟" إلزاميا بدلا من اختياري diff --git a/config/locales/simple_form.bg.yml b/config/locales/simple_form.bg.yml index a4a2027137..f14a21b0c7 100644 --- a/config/locales/simple_form.bg.yml +++ b/config/locales/simple_form.bg.yml @@ -77,11 +77,13 @@ bg: warn: Скриване на филтрираното съдържание зад предупреждение, споменавайки заглавието на филтъра form_admin_settings: activity_api_enabled: Броят на местните публикувани публикации, дейни потребители и нови регистрации в седмични кофи + app_icon: WEBP, PNG, GIF или JPG. Заменя подразбиращата се икона на приложението в мобилни устройства с произволна икона. backups_retention_period: Потребителите имат способността да пораждат архиви от публикациите си за по-късно изтегляне. Задавайки положителна стойност, тези архиви самодейно ще се изтрият от хранилището ви след определения брой дни. bootstrap_timeline_accounts: Тези акаунти ще се закачат в горния край на препоръките за следване на нови потребители. closed_registrations_message: Показва се, когато е затворено за регистрации content_cache_retention_period: Всички публикации от други сървъри, включително подсилвания и отговори, ще се изтрият след посочения брой дни, без да се взема предвид каквото и да е взаимодействие на местния потребител с тези публикации. Това включва публикации, които местния потребител е означил като отметки или любими. Личните споменавания между потребители от различни инстанции също ще се загубят и невъзможно да се възстановят. Употребата на тази настройка е предназначена за случаи със специално предназначение и разбива очакванията на много потребители, когато се изпълнява за употреба с общо предназначение. custom_css: Може да прилагате собствени стилове в уебверсията на Mastodon. + favicon: WEBP, PNG, GIF или JPG. Заменя стандартната сайтоикона на Mastodon с произволна икона. mascot: Замества илюстрацията в разширения уеб интерфейс. media_cache_retention_period: Мултимедийни файлове от публикации, направени от отдалечени потребители, се сринаха в сървъра ви. Задавайки положителна стойност, мултимедията ще се изтрие след посочения брой дни. Ако се искат мултимедийни данни след изтриването, то ще се изтегли пак, ако още е наличен източникът на съдържание. Поради ограниченията за това колко често картите за предварващ преглед на връзките анкетират сайтове на трети страни, се препоръчва да зададете тази стойност на поне 14 дни или картите за предварващ преглед на връзките няма да се обновяват при поискване преди този момент. peers_api_enabled: Списък от имена на домейни, с които сървърът се е свързал във федивселената. Тук не се включват данни за това дали федерирате с даден сървър, а само за това дали сървърът ви знае за него. Това се ползва от услуги, събиращи статистика за федерацията в общия смисъл. diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index c1056260bb..7d39786697 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -77,13 +77,13 @@ de: warn: Den gefilterten Beitrag hinter einer Warnung, die den Filtertitel beinhaltet, ausblenden form_admin_settings: activity_api_enabled: Anzahl der wöchentlichen Beiträge, aktiven Profile und Registrierungen auf diesem Server - app_icon: WEBP, PNG, GIF oder JPG Überschreibt das Standard-App-Symbol auf mobilen Geräten mit einem benutzerdefinierten Symbol. + app_icon: WEBP, PNG, GIF oder JPG. Überschreibt das Standard-App-Symbol auf mobilen Geräten mit einem eigenen Symbol. backups_retention_period: Nutzer*innen haben die Möglichkeit, Archive ihrer Beiträge zu erstellen, die sie später herunterladen können. Wenn ein positiver Wert gesetzt ist, werden diese Archive nach der festgelegten Anzahl von Tagen automatisch aus deinem Speicher gelöscht. bootstrap_timeline_accounts: Diese Konten werden bei den Follower-Empfehlungen für neu registrierte Nutzer*innen oben angeheftet. closed_registrations_message: Wird angezeigt, wenn Registrierungen deaktiviert sind content_cache_retention_period: Sämtliche Beiträge von anderen Servern (einschließlich geteilte Beiträge und Antworten) werden, unabhängig von der Interaktion der lokalen Nutzer*innen mit diesen Beiträgen, nach der festgelegten Anzahl von Tagen gelöscht. Das betrifft auch Beiträge, die von lokalen Nutzer*innen favorisiert oder als Lesezeichen gespeichert wurden. Private Erwähnungen zwischen Nutzer*innen von verschiedenen Servern werden ebenfalls verloren gehen und können nicht wiederhergestellt werden. Das Verwenden dieser Option richtet sich ausschließlich an Server für spezielle Zwecke und wird die allgemeine Nutzungserfahrung beeinträchtigen, wenn sie für den allgemeinen Gebrauch aktiviert ist. custom_css: Du kannst benutzerdefinierte Stile auf die Web-Version von Mastodon anwenden. - favicon: WEBP, PNG, GIF oder JPG überschreibt das Standard-Mastodon favicon mit einem benutzerdefinierten Icon. + favicon: WEBP, PNG, GIF oder JPG. Überschreibt das Standard-Mastodon-Favicon mit einem eigenen Symbol. mascot: Überschreibt die Abbildung in der erweiterten Weboberfläche. media_cache_retention_period: Mediendateien aus Beiträgen von externen Nutzer*innen werden auf deinem Server zwischengespeichert. Wenn ein positiver Wert gesetzt ist, werden die Medien nach der festgelegten Anzahl von Tagen gelöscht. Sollten die Medien nach dem Löschvorgang wieder angefragt werden, werden sie erneut heruntergeladen, sofern der ursprüngliche Inhalt noch vorhanden ist. Es wird empfohlen, diesen Wert auf mindestens 14 Tage festzulegen, da die Häufigkeit der Abfrage von Linkvorschaukarten für Websites von Dritten begrenzt ist und die Linkvorschaukarten sonst nicht vor Ablauf dieser Zeit aktualisiert werden. peers_api_enabled: Eine Liste von Domains, die diesem Server im Fediverse begegnet sind. Hierbei werden keine Angaben darüber gemacht, ob du mit einem bestimmten Server föderierst, sondern nur, dass dein Server davon weiß. Dies wird von Diensten verwendet, die allgemein Statistiken übers Ferdiverse sammeln. diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml index 8fee5b414d..6ccca2bc84 100644 --- a/config/locales/simple_form.hu.yml +++ b/config/locales/simple_form.hu.yml @@ -83,7 +83,7 @@ hu: closed_registrations_message: Akkor jelenik meg, amikor a regisztráció le van zárva content_cache_retention_period: Minden más kiszolgálóról származó bejegyzés (megtolásokkal és válaszokkal együtt) törölve lesz a megadott számú nap elteltével, függetlenül a helyi felhasználók ezekkel a bejegyzésekkel történő interakcióitól. Ebben azok a bejegyzések is benne vannak, melyeket a helyi felhasználó könyvjelzőzött vagy kedvencnek jelölt. A különböző kiszolgálók felhasználói közötti privát üzenetek is el fognak veszni visszaállíthatatlanul. Ennek a beállításnak a használata különleges felhasználási esetekre javasolt, mert számos felhasználói elvárás fog eltörni, ha általános céllal használják. custom_css: A Mastodon webes verziójában használhatsz egyéni stílusokat. - favicon: WEBP, PNG, GIF vagy JPG. Az alapértelmezett Mastodon favicon felülírása egy egyéni ikonnal. + favicon: WEBP, PNG, GIF vagy JPG. Az alapértelmezett Mastodon favicont felülírja egy egyéni ikonnal. mascot: Felülbírálja a speciális webes felületen található illusztrációt. media_cache_retention_period: A távoli felhasználók bejegyzéseinek médiatartalmait a kiszolgálód gyorsítótárazza. Ha pozitív értékre állítják, ezek a médiatartalmak a megadott számú nap után törölve lesznek. Ha a médiát újra lekérik, miután törlődött, újra le fogjuk tölteni, ha az eredeti még elérhető. A hivatkozások előnézeti kártyáinak harmadik fél weboldalai felé történő hivatkozásaira alkalmazott megkötései miatt javasolt, hogy ezt az értéket legalább 14 napra állítsuk, ellenkező esetben a hivatkozások előnézeti kártyái szükség esetén nem fognak tudni frissülni ezen idő előtt. peers_api_enabled: Azon domainek listája, melyekkel ez a kiszolgáló találkozott a fediverzumban. Nem csatolunk adatot arról, hogy föderált kapcsolatban vagy-e az adott kiszolgálóval, csak arról, hogy a kiszolgálód tud a másikról. Ezt olyan szolgáltatások használják, melyek általában a föderációról készítenek statisztikákat. diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index c796cb5fac..51329edd88 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -77,11 +77,13 @@ ia: warn: Celar le contento filtrate detra un aviso citante le titulo del filtro form_admin_settings: activity_api_enabled: Numeros de messages localmente publicate, usatores active, e nove registrationes in gruppos septimanal + app_icon: WEBP, PNG, GIF o JPG. Supplanta le icone predefinite sur apparatos mobile con un icone personalisate. backups_retention_period: Le usatores pote generar archivos de lor messages pro discargar los plus tarde. Quando predefinite a un valor positive, iste archivos sera automaticamente delite de tu immagazinage post le specificate numero de dies. bootstrap_timeline_accounts: Iste contos sera appunctate al summitate del recommendationes a sequer del nove usatores. closed_registrations_message: Monstrate quando le inscriptiones es claudite content_cache_retention_period: Tote messages de altere servitores (includite stimulos e responsas) sera delite post le specificate numero de dies, sin considerar alcun interaction de usator local con ille messages. Isto include messages ubi un usator local los ha marcate como marcapaginas o favoritos. Mentiones private inter usatores de differente instantias sera alsi perdite e impossibile a restaurar. Le uso de iste parametros es intendite pro specific instantias e infringe multe expectationes de usator quando implementate pro uso general. custom_css: Tu pote applicar stilos personalisate sur le version de web de Mastodon. + favicon: WEBP, PNG, GIF o JPG. Supplanta le favicone predefinite de Mastodon con un icone personalisate. mascot: Illo substitue le illustration in le interfacie web avantiate. media_cache_retention_period: Le files multimedial de messages producite per usatores remote es in cache sur tu servitor. Quando predefinite a un valor positive, le medios sera delite post le numero de dies specificate. Le datos multimedial requirite post que illo es delite, sera re-discargate, si le contento original sera ancora disponibile. Per limitationes sur le frequentia con que le schedas de pre-visualisation de ligamine scruta le sitos de tertie partes, il es recommendate de predefinir iste valor a al minus 14 dies, o le schedas de pre-visualisation de ligamine non sera actualisate sur demanda ante ille tempore. peers_api_enabled: Un lista de nomines de dominio que iste servitor ha incontrate in le fediverso. Nulle datos es includite ci re tu federation con un date servitor, justo que tu servitor lo cognosce. Isto es usate per servicios que collige statistica re le federation in senso general. diff --git a/config/locales/simple_form.it.yml b/config/locales/simple_form.it.yml index 5c0e6aa4e8..f5624344b9 100644 --- a/config/locales/simple_form.it.yml +++ b/config/locales/simple_form.it.yml @@ -77,11 +77,13 @@ it: warn: Nascondi il contenuto filtrato e mostra invece un avviso, citando il titolo del filtro form_admin_settings: activity_api_enabled: Conteggi di post pubblicati localmente, utenti attivi e nuove registrazioni in gruppi settimanali + app_icon: WEBP, PNG, GIF o JPG. Sostituisce l'icona dell'app predefinita sui dispositivi mobili con un'icona personalizzata. backups_retention_period: Gli utenti hanno la possibilità di generare archivi dei propri post da scaricare successivamente. Se impostati su un valore positivo, questi archivi verranno automaticamente eliminati dallo spazio di archiviazione dopo il numero di giorni specificato. bootstrap_timeline_accounts: Questi account verranno aggiunti in cima ai consigli da seguire dei nuovi utenti. closed_registrations_message: Visualizzato alla chiusura delle iscrizioni content_cache_retention_period: Tutti i post da altri server (inclusi booster e risposte) verranno eliminati dopo il numero specificato di giorni, senza tener conto di eventuali interazioni con gli utenti locali con tali post. Questo include i post in cui un utente locale ha contrassegnato come segnalibri o preferiti. Anche le menzioni private tra utenti di diverse istanze andranno perse e impossibile da ripristinare. L'uso di questa impostazione è inteso per casi di scopo speciale e rompe molte aspettative dell'utente quando implementato per uso generale. custom_css: È possibile applicare stili personalizzati sulla versione web di Mastodon. + favicon: WEBP, PNG, GIF o JPG. Sostituisce la favicon predefinita di Mastodon con un'icona personalizzata. mascot: Sostituisce l'illustrazione nell'interfaccia web avanzata. media_cache_retention_period: I file multimediali da post fatti da utenti remoti sono memorizzati nella cache sul tuo server. Quando impostato a un valore positivo, i media verranno eliminati dopo il numero specificato di giorni. Se i dati multimediali sono richiesti dopo che sono stati eliminati, saranno nuovamente scaricati, se il contenuto sorgente è ancora disponibile. A causa di restrizioni su quanto spesso link anteprima carte sondaggio siti di terze parti, si consiglia di impostare questo valore ad almeno 14 giorni, o le schede di anteprima link non saranno aggiornate su richiesta prima di quel tempo. peers_api_enabled: Un elenco di nomi di dominio che questo server ha incontrato nel fediverse. Qui non sono inclusi dati sul fatto se si federano con un dato server, solo che il server ne è a conoscenza. Questo viene utilizzato dai servizi che raccolgono statistiche sulla federazione in senso generale. diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index 6ab4e03222..df4755c4fb 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -77,9 +77,11 @@ ko: warn: 필터 제목을 언급하는 경고 뒤에 걸러진 내용을 숨기기 form_admin_settings: activity_api_enabled: 주별 로컬에 게시된 글, 활성 사용자 및 새로운 가입자 수 + app_icon: WEBP, PNG, GIF 또는 JPG. 모바일 기기에 쓰이는 기본 아이콘을 대체합니다. bootstrap_timeline_accounts: 이 계정들은 팔로우 추천 목록 상단에 고정됩니다. closed_registrations_message: 새 가입을 차단했을 때 표시됩니다 custom_css: 사용자 지정 스타일을 웹 버전의 마스토돈에 지정할 수 있습니다. + favicon: WEBP, PNG, GIF 또는 JPG. 기본 파비콘을 대체합니다. mascot: 고급 웹 인터페이스의 그림을 대체합니다. peers_api_enabled: 이 서버가 연합우주에서 만났던 서버들에 대한 도메인 네임의 목록입니다. 해당 서버와 어떤 연합을 했는지에 대한 정보는 전혀 포함되지 않고, 단순히 그 서버를 알고 있는지에 대한 것입니다. 이것은 일반적으로 연합에 대한 통계를 수집할 때 사용됩니다. profile_directory: 프로필 책자는 발견되기를 희망하는 모든 사람들의 목록을 나열합니다. @@ -240,6 +242,7 @@ ko: backups_retention_period: 사용자 아카이브 유지 기한 bootstrap_timeline_accounts: 새로운 사용자들에게 추천할 계정들 closed_registrations_message: 가입이 불가능 할 때의 사용자 지정 메시지 + content_cache_retention_period: 리모트 콘텐츠 보유 기간 custom_css: 사용자 정의 CSS mascot: 사용자 정의 마스코트 (legacy) media_cache_retention_period: 미디어 캐시 유지 기한 diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index 1be95a9f1b..6631b59b19 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -49,7 +49,7 @@ lt: header: WEBP, PNG, GIF arba JPG. Ne daugiau kaip %{size}. Bus sumažintas iki %{dimensions} tšk. inbox_url: Nukopijuok URL adresą iš pradinio puslapio perdavėjo, kurį nori naudoti irreversible: Filtruoti įrašai išnyks negrįžtamai, net jei vėliau filtras bus pašalintas - locale: Naudotojo sąsajos kalba, el. laiškai ir stumiamieji pranešimai + locale: Naudotojo sąsajos kalba, el. laiškai ir tiesioginiai pranešimai password: Naudok bent 8 simbolius phrase: Bus suderinta, neatsižvelgiant į teksto lygį arba įrašo turinio įspėjimą scopes: Prie kurių API programai bus leidžiama pasiekti. Pasirinkus aukščiausio lygio sritį, atskirų sričių pasirinkti nereikia. diff --git a/config/locales/simple_form.nn.yml b/config/locales/simple_form.nn.yml index bdd3db040d..a93a803221 100644 --- a/config/locales/simple_form.nn.yml +++ b/config/locales/simple_form.nn.yml @@ -77,12 +77,13 @@ nn: warn: Skjul det filtrerte innhaldet bak ei åtvaring som nemner tittelen på filteret form_admin_settings: activity_api_enabled: Tal på lokale innlegg, aktive brukarar og nyregistreringar kvar veke - app_icon: WEBP, PNG, GIF eller JPG. Overstyrer standard-ikonet på mobile einingar med eit tilpassa ikon. + app_icon: WEBP, PNG, GIF eller JPG. Overstyrer standard-app-ikonet på mobile einingar med eit eigendefinert ikon. backups_retention_period: Brukarar har moglegheit til å generere arkiv av sine innlegg for å laste ned seinare. Når sett til ein positiv verdi, blir desse arkiva automatisk sletta frå lagringa etter eit gitt antal dagar. bootstrap_timeline_accounts: Desse kontoane vil bli festa øverst på fylgjaranbefalingane til nye brukarar. closed_registrations_message: Vist når det er stengt for registrering content_cache_retention_period: Alle innlegg frå andre serverar (inkludert boostar og svar) vil bli sletta etter dei gitte antal dagar, uten hensyn til lokale brukarinteraksjonar med desse innlegga. Dette inkluderer innlegg der ein lokal brukar har merka det som bokmerker eller som favorittar. Òg private nemningar mellom brukarar frå ulike førekomstar vil gå tapt og vere umogleg å gjenskape. Bruk av denne innstillinga er rekna på spesielle førekomstar og bryt mange brukarforventingar når dette blir tatt i generell bruk. custom_css: Du kan bruka eigendefinerte stilar på nettversjonen av Mastodon. + favicon: WEBP, PNG, GIF eller JPG. Overstyrer det standarde Mastodon-favikonet med eit eigendefinert ikon. mascot: Overstyrer illustrasjonen i det avanserte webgrensesnittet. media_cache_retention_period: Mediafiler frå innlegg laga av eksterne brukarar blir bufra på serveren din. Når sett til ein positiv verdi, slettast media etter eit gitt antal dagar. Viss mediedata blir førespurt etter det er sletta, vil dei bli lasta ned på nytt viss kjelda sitt innhald framleis er tilgjengeleg. På grunn av restriksjonar på kor ofte lenkeførehandsvisningskort lastar tredjepart-nettstadar, rådast det til å setje denne verdien til minst 14 dagar, eller at førehandsvisningskort ikkje blir oppdatert på førespurnad før det tidspunktet. peers_api_enabled: Ei liste over domenenamn denne tenaren har møtt på i allheimen. Det står ingenting om tenaren din samhandlar med ein annan tenar, berre om tenaren din veit om den andre. Dette blir brukt av tenester som samlar statistikk om føderering i det heile. diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml index 9044546f2b..77a0d8cd6f 100644 --- a/config/locales/simple_form.pt-BR.yml +++ b/config/locales/simple_form.pt-BR.yml @@ -77,10 +77,15 @@ pt-BR: warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro form_admin_settings: activity_api_enabled: Contagem de publicações locais, usuários ativos e novos usuários semanais + app_icon: WEBP, PNG, GIF ou JPG. Sobrescrever o ícone padrão do aplicativo em dispositivos móveis com um ícone personalizado. + backups_retention_period: Os usuários têm a capacidade de gerar arquivos de suas postagens para baixar mais tarde. Quando definido como um valor positivo, esses arquivos serão automaticamente excluídos do seu armazenamento após o número especificado de dias. bootstrap_timeline_accounts: Estas contas serão fixadas no topo das recomendações de novos usuários para seguir. closed_registrations_message: Exibido quando as inscrições estiverem fechadas + content_cache_retention_period: Todas as postagens de outros servidores (incluindo boosts e respostas) serão excluídas após o número especificado de dias, sem levar a qualquer interação do usuário local com esses posts. Isto inclui postagens onde um usuário local o marcou como favorito ou favoritos. Menções privadas entre usuários de diferentes instâncias também serão perdidas e impossíveis de restaurar. O uso desta configuração destina-se a instâncias especiais de propósitos e quebra muitas expectativas dos usuários quando implementadas para uso de propósito geral. custom_css: Você pode aplicar estilos personalizados na versão da web do Mastodon. + favicon: WEBP, PNG, GIF ou JPG. Sobrescreve o favicon padrão do Mastodon com um ícone personalizado. mascot: Substitui a ilustração na interface web avançada. + media_cache_retention_period: Arquivos de mídia de mensagens de usuários remotos são armazenados em cache no seu servidor. Quando definido como valor positivo, a mídia será excluída após o número especificado de dias. Se os dados da mídia forem solicitados depois de excluídos, eles serão baixados novamente, se o conteúdo fonte ainda estiver disponível. Devido a restrições de quantas vezes os cartões de visualização de links sondam sites de terceiros, é recomendado definir este valor em pelo menos 14 dias, ou pré-visualização de links não serão atualizados a pedido antes desse tempo. peers_api_enabled: Uma lista de nomes de domínio que este servidor encontrou no "fediverse". Nenhum dado é incluído aqui sobre se você concorda com os padroes operacionais de um determinado servidor, apenas que o seu servidor sabe disso. Esta ferramenta é utilizado por serviços que recolhem estatísticas sob as normas da federação (grupo de empresas que concordam sob paramentros operacionais específicos), em termos gerais. profile_directory: O diretório de perfis lista todos os usuários que optaram por permitir que suas contas sejam descobertas. require_invite_text: 'Quando o cadastro de novas contas exigir aprovação manual, tornar obrigatório, ao invés de opcional, o texto de solicitação de convite: "Por que você deseja ingressar nessa comunidade?"' diff --git a/config/locales/simple_form.ro.yml b/config/locales/simple_form.ro.yml index 5593022708..dfb44c7745 100644 --- a/config/locales/simple_form.ro.yml +++ b/config/locales/simple_form.ro.yml @@ -163,5 +163,6 @@ ro: 'no': Nu recommended: Recomandat required: + mark: "*" text: obligatoriu 'yes': Da diff --git a/config/locales/simple_form.sq.yml b/config/locales/simple_form.sq.yml index d545f2cd34..c3c3920962 100644 --- a/config/locales/simple_form.sq.yml +++ b/config/locales/simple_form.sq.yml @@ -77,11 +77,13 @@ sq: warn: Fshihe lëndën e filtruar pas një sinjalizimi që përmend titullin e filtrit form_admin_settings: activity_api_enabled: Numër postimesh të botuar lokalisht, përdoruesish aktiv dhe regjistrimesh të reja sipas matjesh javore + app_icon: WEBP, PNG, GIF, ose JPG. Anashkalon ikonë parazgjedhje aplikacioni në pajisje celulare me një ikonë vetjake. backups_retention_period: Përdorues kanë aftësinë të prodhojnë arkiva të postimeve të tyre për t’i shkarkuar më vonë. Kur i jepet një vlerë pozitive, këto arkiva do të fshihen automatikisht prej depozitës tuaj pas numrit të dhënë të ditëve. bootstrap_timeline_accounts: Këto llogari do të fiksohen në krye të rekomandimeve për ndjekje nga përdorues të rinj. closed_registrations_message: Shfaqur kur mbyllen dritare regjistrimesh content_cache_retention_period: Krejt postimet prej shërbyesve të tjerë (përfshi përforcime dhe përgjigje) do të fshihen pas numrit të caktuar të ditëve, pa marrë parasysh çfarëdo ndërveprimi përdoruesi me këto postime. Kjo përfshin postime kur një përdorues vendor u ka vënë shenjë si faqerojtës, ose të parapëlqyer. Do të humbin gjithashtu dhe përmendje private mes përdoruesish nga instanca të ndryshme dhe s’do të jetë e mundshme të rikthehen. Përdorimi i këtij rregullimi është menduar për instanca me qëllim të caktuar dhe ndërhyn në çka presin mjaft përdorues, kur sendërtohet për përdorim të përgjithshëm. custom_css: Stile vetjakë mund të aplikoni në versionin web të Mastodon-it. + favicon: WEBP, PNG, GIF, ose JPG. Anashkalon favikonën parazgjedhje Mastodon me një ikonë vetjake. mascot: Anashkalon ilustrimin te ndërfaqja web e thelluar. media_cache_retention_period: Kartela media nga postime të bëra nga përdorues të largët ruhen në një fshehtinë në shërbyesin tuaj. Kur i jepet një vlerë pozitive, media do të fshihet pas numrit të dhënë të ditëve. Nëse të dhënat e medias duhen pas fshirjes, do të rishkarkohen, nëse lënda burim mund të kihet ende. Për shkak kufizimesh mbi sa shpesh skeda paraparjesh lidhjesh ndërveprojnë me sajte palësh të treta, rekomandohet të vihet kjo vlerë të paktën 14 ditë, ose skedat e paraparjes së lidhje s’do të përditësohen duke e kërkuar para asaj kohe. peers_api_enabled: Një listë emrash përkatësish që ky shërbyes ka hasur në fedivers. Këtu s’jepen të dhëna nëse jeni i federuar me shërbyesin e dhënë, thjesht tregohet se shërbyesi juaj e njeh. Kjo përdoret nga shërbime që mbledhin statistika mbi federimin në kuptimin e përgjithshëm. diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 5d0ebe2de0..71e84a1d54 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -671,7 +671,7 @@ uk: delete_html: 'Ви збираєтеся вилучити деякі з дописів @%{acct}. Це буде:' mark_as_sensitive_html: 'Ви збираєтеся позначити деякі з дописів @%{acct} делікатними. Це буде:' silence_html: 'Ви збираєтеся обмежити обліковий запис @%{acct}. Це буде:' - suspend_html: 'Ви збираєтесь призупинити обліковий запис @%%{acct}. Це буде:' + suspend_html: 'Ви збираєтесь призупинити обліковий запис @%{acct}. Це буде:' actions: delete_html: Вилучити образливі дописи mark_as_sensitive_html: Позначити медіа образливих дописів делікатними From 040aaf3a48022edab19ac42980a6c5a991156ec9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 May 2024 05:42:01 -0400 Subject: [PATCH 122/658] Use `default: ...` assignment for Devise config, fixes `Style/ClassVars` cop (#30214) --- .rubocop_todo.yml | 4 --- config/initializers/devise.rb | 51 ++++++++++++----------------------- 2 files changed, 17 insertions(+), 38 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 25b573017b..4d20330e0e 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -54,10 +54,6 @@ Style/ClassEqualityComparison: - 'app/helpers/jsonld_helper.rb' - 'app/serializers/activitypub/outbox_serializer.rb' -Style/ClassVars: - Exclude: - - 'config/initializers/devise.rb' - # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowedVars. Style/FetchEnvVar: diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index f935090efc..a95c7437fa 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -38,42 +38,25 @@ Warden::Manager.before_logout do |_, warden| end module Devise - mattr_accessor :pam_authentication - @@pam_authentication = false - mattr_accessor :pam_controlled_service - @@pam_controlled_service = nil + mattr_accessor :pam_authentication, default: false + mattr_accessor :pam_controlled_service, default: nil - mattr_accessor :check_at_sign - @@check_at_sign = false + mattr_accessor :check_at_sign, default: false - mattr_accessor :ldap_authentication - @@ldap_authentication = false - mattr_accessor :ldap_host - @@ldap_host = nil - mattr_accessor :ldap_port - @@ldap_port = nil - mattr_accessor :ldap_method - @@ldap_method = nil - mattr_accessor :ldap_base - @@ldap_base = nil - mattr_accessor :ldap_uid - @@ldap_uid = nil - mattr_accessor :ldap_mail - @@ldap_mail = nil - mattr_accessor :ldap_bind_dn - @@ldap_bind_dn = nil - mattr_accessor :ldap_password - @@ldap_password = nil - mattr_accessor :ldap_tls_no_verify - @@ldap_tls_no_verify = false - mattr_accessor :ldap_search_filter - @@ldap_search_filter = nil - mattr_accessor :ldap_uid_conversion_enabled - @@ldap_uid_conversion_enabled = false - mattr_accessor :ldap_uid_conversion_search - @@ldap_uid_conversion_search = nil - mattr_accessor :ldap_uid_conversion_replace - @@ldap_uid_conversion_replace = nil + mattr_accessor :ldap_authentication, default: false + mattr_accessor :ldap_host, default: nil + mattr_accessor :ldap_port, default: nil + mattr_accessor :ldap_method, default: nil + mattr_accessor :ldap_base, default: nil + mattr_accessor :ldap_uid, default: nil + mattr_accessor :ldap_mail, default: nil + mattr_accessor :ldap_bind_dn, default: nil + mattr_accessor :ldap_password, default: nil + mattr_accessor :ldap_tls_no_verify, default: false + mattr_accessor :ldap_search_filter, default: nil + mattr_accessor :ldap_uid_conversion_enabled, default: false + mattr_accessor :ldap_uid_conversion_search, default: nil + mattr_accessor :ldap_uid_conversion_replace, default: nil module Strategies class PamAuthenticatable From fa43a6c8355ae53c0609999e1891023626ab4217 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 May 2024 05:43:59 -0400 Subject: [PATCH 123/658] Use more accurate `redirect_uri` in oauth spec (#30212) --- spec/system/oauth_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/oauth_spec.rb b/spec/system/oauth_spec.rb index 060978217f..3b98ad352b 100644 --- a/spec/system/oauth_spec.rb +++ b/spec/system/oauth_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Using OAuth from an external app' do - let(:client_app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/health', scopes: 'read') } + let(:client_app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: about_url(host: Rails.application.config.x.local_domain), scopes: 'read') } context 'when the user is already logged in' do let!(:user) { Fabricate(:user) } From f3f63107f263db86021565dad79be497db9e5257 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 11:59:15 +0200 Subject: [PATCH 124/658] Update dependency @reduxjs/toolkit to v2.2.4 (#30223) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 28cf500466..9aa8125d58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3047,13 +3047,13 @@ __metadata: linkType: hard "@reduxjs/toolkit@npm:^2.0.1": - version: 2.2.3 - resolution: "@reduxjs/toolkit@npm:2.2.3" + version: 2.2.4 + resolution: "@reduxjs/toolkit@npm:2.2.4" dependencies: immer: "npm:^10.0.3" redux: "npm:^5.0.1" redux-thunk: "npm:^3.1.0" - reselect: "npm:^5.0.1" + reselect: "npm:^5.1.0" peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 @@ -3062,7 +3062,7 @@ __metadata: optional: true react-redux: optional: true - checksum: 10c0/f10f2c8f4b6c5c7a65d8d60246bdfde86b6cd2f542210ebdda8002223c7f4e99ed32964825e63f37345d9d12532671150fcec2809a40690931ae44afe8aba7f8 + checksum: 10c0/fdbf510210a5aa4864432397e1a9469367e297cd1d9c09a82e68638df7555672c2f8511fe76f933b00efbbb233c534831591772a44e8c41233e34f3cd0f54569 languageName: node linkType: hard @@ -14987,10 +14987,10 @@ __metadata: languageName: node linkType: hard -"reselect@npm:^5.0.1": - version: 5.0.1 - resolution: "reselect@npm:5.0.1" - checksum: 10c0/0724b4555cd6411849de334a75177780f127af849eb71c4b709966d07ade8090d125c0c926dc6cf936866d23ebadda6aad1da93cd8340525323b889f25d56d51 +"reselect@npm:^5.1.0": + version: 5.1.0 + resolution: "reselect@npm:5.1.0" + checksum: 10c0/b0ed789f4f6f10dfbd23741823726793384932969aa7ce8f584c882ad87620a02b09b5d1146cd2ea6eaa0953b3fd9f7df22f113893af73f35f28432a8a4294de languageName: node linkType: hard From e20f2e7300d326bd637bec691607ad4c0e70dc8f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 May 2024 08:34:20 -0400 Subject: [PATCH 125/658] Update i18n to version 1.14.5 (#30198) --- Gemfile | 2 +- Gemfile.lock | 19 +++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Gemfile b/Gemfile index eb507e9d18..c7e07f9642 100644 --- a/Gemfile +++ b/Gemfile @@ -57,7 +57,7 @@ gem 'htmlentities', '~> 4.3' gem 'http', '~> 5.2.0' gem 'http_accept_language', '~> 2.1' gem 'httplog', '~> 1.6.2' -gem 'i18n', '1.14.1' # TODO: Remove version when resolved: https://github.com/glebm/i18n-tasks/issues/552 / https://github.com/ruby-i18n/i18n/pull/688 +gem 'i18n' gem 'idn-ruby', require: 'idn' gem 'inline_svg' gem 'kaminari', '~> 1.2' diff --git a/Gemfile.lock b/Gemfile.lock index 9df960e618..b4db2b9a07 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -130,14 +130,7 @@ GEM erubi (>= 1.0.0) rack (>= 0.9.0) rouge (>= 1.0.0) - better_html (2.1.1) - actionview (>= 6.0) - activesupport (>= 6.0) - ast (~> 2.0) - erubi (~> 1.4) - parser (>= 2.4) - smart_properties - bigdecimal (3.1.7) + bigdecimal (3.1.8) bindata (2.5.0) binding_of_caller (1.0.1) debug_inspector (>= 1.2.0) @@ -328,12 +321,11 @@ GEM httplog (1.6.3) rack (>= 2.0) rainbow (>= 2.0.0) - i18n (1.14.1) + i18n (1.14.5) concurrent-ruby (~> 1.0) - i18n-tasks (1.0.13) + i18n-tasks (1.0.14) activesupport (>= 4.0.2) ast (>= 2.1.0) - better_html (>= 1.0, < 3.0) erubi highline (>= 2.0.0) i18n @@ -601,7 +593,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.9.0) - reline (0.5.5) + reline (0.5.6) io-console (~> 0.5) request_store (1.6.0) rack (>= 1.4) @@ -723,7 +715,6 @@ GEM simplecov-html (0.12.3) simplecov-lcov (0.8.0) simplecov_json_formatter (0.1.4) - smart_properties (1.17.0) stackprof (0.2.26) statsd-ruby (1.5.0) stoplight (4.1.0) @@ -860,7 +851,7 @@ DEPENDENCIES http (~> 5.2.0) http_accept_language (~> 2.1) httplog (~> 1.6.2) - i18n (= 1.14.1) + i18n i18n-tasks (~> 1.0) idn-ruby inline_svg From 164b09bfcc7d2b8c3619411ee06f530256d9fe4b Mon Sep 17 00:00:00 2001 From: Joshua Young Date: Fri, 10 May 2024 22:34:32 +1000 Subject: [PATCH 126/658] Update README.md setup steps (#30063) --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d0e75daba..0353a4c675 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre - **PostgreSQL** 12+ - **Redis** 4+ - **Ruby** 3.1+ -- **Node.js** 16+ +- **Node.js** 18+ 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. @@ -91,10 +91,12 @@ A **Vagrant** configuration is included for development purposes. To use it, com To set up **MacOS** for native development, complete the following steps: - Use a Ruby version manager to install the specified version from `.ruby-version` +- Run `bundle` to install required gems - Run `brew install postgresql@14 redis imagemagick libidn` to install required dependencies - Navigate to Mastodon's root directory and run `brew install nvm` then `nvm use` to use the version from `.nvmrc` +- Run `yarn` to install required packages - Run `corepack enable && corepack prepare` -- Run `bundle exec rails db:setup` (optionally prepend `RAILS_ENV=development` to target the dev environment) +- Run `RAILS_ENV=development bundle exec rails db:setup` - Finally, run `bin/dev` which will launch the local services via `overmind` (if installed) or `foreman` ### Docker From 0d397db5dd803fab2b7ddda9ae0dd5c26f4880a6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 May 2024 08:36:09 -0400 Subject: [PATCH 127/658] Consolidate system specs into single directory, use rspec tags for configuration (#30206) --- .github/workflows/test-ruby.yml | 4 ++- .rubocop_todo.yml | 2 +- lib/tasks/spec.rake | 13 ------- spec/rails_helper.rb | 36 ++++++++----------- spec/requests/content_security_policy_spec.rb | 2 +- spec/support/capybara.rb | 4 +++ spec/support/javascript_errors.rb | 2 +- spec/support/streaming_server_manager.rb | 4 +-- .../admin/accounts_spec.rb | 0 .../admin/custom_emojis_spec.rb | 0 .../admin/domain_blocks_spec.rb | 0 .../admin/email_domain_blocks_spec.rb | 0 .../admin/ip_blocks_spec.rb | 0 .../admin/software_updates_spec.rb | 0 .../admin/statuses_spec.rb | 0 .../links/preview_card_providers_spec.rb | 0 .../admin/trends/links_spec.rb | 0 .../admin/trends/statuses_spec.rb | 0 .../admin/trends/tags_spec.rb | 0 spec/{features => system}/captcha_spec.rb | 0 spec/{features => system}/log_in_spec.rb | 0 spec/system/new_statuses_spec.rb | 2 +- spec/system/oauth_spec.rb | 2 +- spec/system/ocr_spec.rb | 2 +- spec/{features => system}/profile_spec.rb | 0 .../{features => system}/redirections_spec.rb | 0 spec/system/report_interface_spec.rb | 2 +- .../severed_relationships_spec.rb | 0 spec/system/share_entrypoint_spec.rb | 2 +- spec/system/unlogged_spec.rb | 2 +- 30 files changed, 32 insertions(+), 47 deletions(-) delete mode 100644 lib/tasks/spec.rake rename spec/{features => system}/admin/accounts_spec.rb (100%) rename spec/{features => system}/admin/custom_emojis_spec.rb (100%) rename spec/{features => system}/admin/domain_blocks_spec.rb (100%) rename spec/{features => system}/admin/email_domain_blocks_spec.rb (100%) rename spec/{features => system}/admin/ip_blocks_spec.rb (100%) rename spec/{features => system}/admin/software_updates_spec.rb (100%) rename spec/{features => system}/admin/statuses_spec.rb (100%) rename spec/{features => system}/admin/trends/links/preview_card_providers_spec.rb (100%) rename spec/{features => system}/admin/trends/links_spec.rb (100%) rename spec/{features => system}/admin/trends/statuses_spec.rb (100%) rename spec/{features => system}/admin/trends/tags_spec.rb (100%) rename spec/{features => system}/captcha_spec.rb (100%) rename spec/{features => system}/log_in_spec.rb (100%) rename spec/{features => system}/profile_spec.rb (100%) rename spec/{features => system}/redirections_spec.rb (100%) rename spec/{features => system}/severed_relationships_spec.rb (100%) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 84b9075708..45dc8a0deb 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -186,6 +186,8 @@ jobs: DISABLE_SIMPLECOV: true RAILS_ENV: test BUNDLE_WITH: test + LOCAL_DOMAIN: localhost:3000 + LOCAL_HTTPS: false strategy: fail-fast: false @@ -215,7 +217,7 @@ jobs: - name: Load database schema run: './bin/rails db:create db:schema:load db:seed' - - run: bundle exec rake spec:system + - run: bin/rspec spec/system --tag streaming --tag js - name: Archive logs uses: actions/upload-artifact@v4 diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 4d20330e0e..91e666d7f4 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -70,7 +70,7 @@ Style/FetchEnvVar: - 'config/initializers/vapid.rb' - 'lib/mastodon/redis_config.rb' - 'lib/tasks/repo.rake' - - 'spec/features/profile_spec.rb' + - 'spec/system/profile_spec.rb' # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle, MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns. diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake deleted file mode 100644 index d505a47195..0000000000 --- a/lib/tasks/spec.rake +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -if Rake::Task.task_defined?('spec:system') - namespace :spec do - task :enable_system_specs do # rubocop:disable Rails/RakeEnvironment - ENV['LOCAL_DOMAIN'] = 'localhost:3000' - ENV['LOCAL_HTTPS'] = 'false' - ENV['RUN_SYSTEM_SPECS'] = 'true' - end - end - - Rake::Task['spec:system'].enhance ['spec:enable_system_specs'] -end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 89fc25bcbd..d8eb561d42 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -3,12 +3,8 @@ ENV['RAILS_ENV'] ||= 'test' # This needs to be defined before Rails is initialized -RUN_SYSTEM_SPECS = ENV.fetch('RUN_SYSTEM_SPECS', false) - -if RUN_SYSTEM_SPECS - STREAMING_PORT = ENV.fetch('TEST_STREAMING_PORT', '4020') - ENV['STREAMING_API_BASE_URL'] = "http://localhost:#{STREAMING_PORT}" -end +STREAMING_PORT = ENV.fetch('TEST_STREAMING_PORT', '4020') +ENV['STREAMING_API_BASE_URL'] = "http://localhost:#{STREAMING_PORT}" require File.expand_path('../config/environment', __dir__) @@ -26,10 +22,12 @@ require 'test_prof/recipes/rspec/before_all' Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } ActiveRecord::Migration.maintain_test_schema! -WebMock.disable_net_connect!(allow: Chewy.settings[:host], allow_localhost: RUN_SYSTEM_SPECS) +WebMock.disable_net_connect!( + allow_localhost: true, + allow: Chewy.settings[:host] +) Sidekiq.logger = nil -# System tests config DatabaseCleaner.strategy = [:deletion] Devise::Test::ControllerHelpers.module_eval do @@ -49,16 +47,14 @@ Devise::Test::ControllerHelpers.module_eval do end RSpec.configure do |config| - # This is set before running spec:system, see lib/tasks/tests.rake - config.filter_run_excluding type: lambda { |type| - case type - when :system - !RUN_SYSTEM_SPECS - end - } + # By default, skip specs that need full JS browser + config.filter_run_excluding :js - # By default, skip the elastic search integration specs - config.filter_run_excluding search: true + # By default, skip specs that need elastic search server + config.filter_run_excluding :search + + # By default, skip specs that need the streaming server + config.filter_run_excluding :streaming config.fixture_paths = [ Rails.root.join('spec', 'fixtures'), @@ -81,7 +77,7 @@ RSpec.configure do |config| config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::ControllerHelpers, type: :helper config.include Devise::Test::ControllerHelpers, type: :view - config.include Devise::Test::IntegrationHelpers, type: :feature + config.include Devise::Test::IntegrationHelpers, type: :system config.include Devise::Test::IntegrationHelpers, type: :request config.include ActionMailer::TestHelper config.include Paperclip::Shoulda::Matchers @@ -111,10 +107,6 @@ RSpec.configure do |config| stub_reset_connection_pools end - config.before :each, type: :feature do - Capybara.current_driver = :rack_test - end - config.before do |example| allow(Resolv::DNS).to receive(:open).and_raise('Real DNS queries are disabled, stub Resolv::DNS as needed') unless example.metadata[:type] == :system end diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index d4447dca4b..ba6fe47741 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -23,7 +23,7 @@ describe 'Content-Security-Policy' do <<~CSP.split("\n").map(&:strip) base-uri 'none' child-src 'self' blob: https://cb6e6126.ngrok.io - connect-src 'self' data: blob: https://cb6e6126.ngrok.io ws://cb6e6126.ngrok.io:4000 + connect-src 'self' data: blob: https://cb6e6126.ngrok.io #{Rails.configuration.x.streaming_api_base_url} default-src 'none' font-src 'self' https://cb6e6126.ngrok.io form-action 'self' diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index d4f27e209e..be1378ffac 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -26,6 +26,10 @@ Capybara.javascript_driver = :headless_chrome RSpec.configure do |config| config.before(:each, type: :system) do + driven_by :rack_test + end + + config.before(:each, :js, type: :system) do driven_by Capybara.javascript_driver end end diff --git a/spec/support/javascript_errors.rb b/spec/support/javascript_errors.rb index a36bf6017e..28a43b3b8a 100644 --- a/spec/support/javascript_errors.rb +++ b/spec/support/javascript_errors.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.configure do |config| - config.after(:each, type: :system) do + config.after(:each, :js, type: :system) do errors = page.driver.browser.logs.get(:browser) if errors.present? aggregate_failures 'javascript errrors' do diff --git a/spec/support/streaming_server_manager.rb b/spec/support/streaming_server_manager.rb index b702fc77ce..3facf16b8e 100644 --- a/spec/support/streaming_server_manager.rb +++ b/spec/support/streaming_server_manager.rb @@ -95,7 +95,7 @@ RSpec.configure do |config| end end - config.around :each, type: :system do |example| + config.around :each, :streaming, type: :system do |example| # Streaming server needs DB access but `use_transactional_tests` rolls back # every transaction. Disable this feature for streaming tests, and use # DatabaseCleaner to clean the database tables between each test. @@ -125,6 +125,6 @@ RSpec.configure do |config| end def streaming_examples_present? - RUN_SYSTEM_SPECS + RSpec.world.filtered_examples.values.flatten.any? { |example| example.metadata[:streaming] == true } end end diff --git a/spec/features/admin/accounts_spec.rb b/spec/system/admin/accounts_spec.rb similarity index 100% rename from spec/features/admin/accounts_spec.rb rename to spec/system/admin/accounts_spec.rb diff --git a/spec/features/admin/custom_emojis_spec.rb b/spec/system/admin/custom_emojis_spec.rb similarity index 100% rename from spec/features/admin/custom_emojis_spec.rb rename to spec/system/admin/custom_emojis_spec.rb diff --git a/spec/features/admin/domain_blocks_spec.rb b/spec/system/admin/domain_blocks_spec.rb similarity index 100% rename from spec/features/admin/domain_blocks_spec.rb rename to spec/system/admin/domain_blocks_spec.rb diff --git a/spec/features/admin/email_domain_blocks_spec.rb b/spec/system/admin/email_domain_blocks_spec.rb similarity index 100% rename from spec/features/admin/email_domain_blocks_spec.rb rename to spec/system/admin/email_domain_blocks_spec.rb diff --git a/spec/features/admin/ip_blocks_spec.rb b/spec/system/admin/ip_blocks_spec.rb similarity index 100% rename from spec/features/admin/ip_blocks_spec.rb rename to spec/system/admin/ip_blocks_spec.rb diff --git a/spec/features/admin/software_updates_spec.rb b/spec/system/admin/software_updates_spec.rb similarity index 100% rename from spec/features/admin/software_updates_spec.rb rename to spec/system/admin/software_updates_spec.rb diff --git a/spec/features/admin/statuses_spec.rb b/spec/system/admin/statuses_spec.rb similarity index 100% rename from spec/features/admin/statuses_spec.rb rename to spec/system/admin/statuses_spec.rb diff --git a/spec/features/admin/trends/links/preview_card_providers_spec.rb b/spec/system/admin/trends/links/preview_card_providers_spec.rb similarity index 100% rename from spec/features/admin/trends/links/preview_card_providers_spec.rb rename to spec/system/admin/trends/links/preview_card_providers_spec.rb diff --git a/spec/features/admin/trends/links_spec.rb b/spec/system/admin/trends/links_spec.rb similarity index 100% rename from spec/features/admin/trends/links_spec.rb rename to spec/system/admin/trends/links_spec.rb diff --git a/spec/features/admin/trends/statuses_spec.rb b/spec/system/admin/trends/statuses_spec.rb similarity index 100% rename from spec/features/admin/trends/statuses_spec.rb rename to spec/system/admin/trends/statuses_spec.rb diff --git a/spec/features/admin/trends/tags_spec.rb b/spec/system/admin/trends/tags_spec.rb similarity index 100% rename from spec/features/admin/trends/tags_spec.rb rename to spec/system/admin/trends/tags_spec.rb diff --git a/spec/features/captcha_spec.rb b/spec/system/captcha_spec.rb similarity index 100% rename from spec/features/captcha_spec.rb rename to spec/system/captcha_spec.rb diff --git a/spec/features/log_in_spec.rb b/spec/system/log_in_spec.rb similarity index 100% rename from spec/features/log_in_spec.rb rename to spec/system/log_in_spec.rb diff --git a/spec/system/new_statuses_spec.rb b/spec/system/new_statuses_spec.rb index 5a3f1b406b..725ea8fe52 100644 --- a/spec/system/new_statuses_spec.rb +++ b/spec/system/new_statuses_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'NewStatuses', :sidekiq_inline do +describe 'NewStatuses', :js, :sidekiq_inline, :streaming do include ProfileStories subject { page } diff --git a/spec/system/oauth_spec.rb b/spec/system/oauth_spec.rb index 3b98ad352b..1c9aca3114 100644 --- a/spec/system/oauth_spec.rb +++ b/spec/system/oauth_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'Using OAuth from an external app' do +describe 'Using OAuth from an external app', :js, :streaming do let(:client_app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: about_url(host: Rails.application.config.x.local_domain), scopes: 'read') } context 'when the user is already logged in' do diff --git a/spec/system/ocr_spec.rb b/spec/system/ocr_spec.rb index 254efa7137..4f4941adca 100644 --- a/spec/system/ocr_spec.rb +++ b/spec/system/ocr_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'OCR', :paperclip_processing, :sidekiq_inline do +describe 'OCR', :js, :paperclip_processing, :sidekiq_inline, :streaming do include ProfileStories let(:email) { 'test@example.com' } diff --git a/spec/features/profile_spec.rb b/spec/system/profile_spec.rb similarity index 100% rename from spec/features/profile_spec.rb rename to spec/system/profile_spec.rb diff --git a/spec/features/redirections_spec.rb b/spec/system/redirections_spec.rb similarity index 100% rename from spec/features/redirections_spec.rb rename to spec/system/redirections_spec.rb diff --git a/spec/system/report_interface_spec.rb b/spec/system/report_interface_spec.rb index 6eba552559..f82604aae8 100644 --- a/spec/system/report_interface_spec.rb +++ b/spec/system/report_interface_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'report interface', :paperclip_processing do +describe 'report interface', :js, :paperclip_processing, :streaming do include ProfileStories let(:email) { 'admin@example.com' } diff --git a/spec/features/severed_relationships_spec.rb b/spec/system/severed_relationships_spec.rb similarity index 100% rename from spec/features/severed_relationships_spec.rb rename to spec/system/severed_relationships_spec.rb diff --git a/spec/system/share_entrypoint_spec.rb b/spec/system/share_entrypoint_spec.rb index 126a816bcc..5fdbeacefa 100644 --- a/spec/system/share_entrypoint_spec.rb +++ b/spec/system/share_entrypoint_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'ShareEntrypoint' do +describe 'ShareEntrypoint', :js, :streaming do include ProfileStories subject { page } diff --git a/spec/system/unlogged_spec.rb b/spec/system/unlogged_spec.rb index c3ebf51d7f..417ccdaeb6 100644 --- a/spec/system/unlogged_spec.rb +++ b/spec/system/unlogged_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'UnloggedBrowsing' do +describe 'UnloggedBrowsing', :js, :streaming do subject { page } before do From 68b9fe824d6cc8154efe46829fa0fcd26a5b9a5d Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 10 May 2024 14:40:20 +0200 Subject: [PATCH 128/658] Add OpenTelemetry instrumentation (#30130) Co-authored-by: Juliano Costa Co-authored-by: Robb Kidd --- Gemfile | 18 +++++ Gemfile.lock | 108 +++++++++++++++++++++++++++ config/initializers/opentelemetry.rb | 63 ++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 config/initializers/opentelemetry.rb diff --git a/Gemfile b/Gemfile index c7e07f9642..247865aacf 100644 --- a/Gemfile +++ b/Gemfile @@ -103,6 +103,24 @@ gem 'rdf-normalize', '~> 0.5' gem 'private_address_check', '~> 0.5' +group :opentelemetry do + gem 'opentelemetry-exporter-otlp', '~> 0.26.3', require: false + gem 'opentelemetry-instrumentation-active_job', '~> 0.7.1', require: false + gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.20.1', require: false + gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.21.2', require: false + gem 'opentelemetry-instrumentation-excon', '~> 0.22.0', require: false + gem 'opentelemetry-instrumentation-faraday', '~> 0.24.1', require: false + gem 'opentelemetry-instrumentation-http', '~> 0.23.2', require: false + gem 'opentelemetry-instrumentation-http_client', '~> 0.22.3', require: false + gem 'opentelemetry-instrumentation-net_http', '~> 0.22.4', require: false + gem 'opentelemetry-instrumentation-pg', '~> 0.27.1', require: false + gem 'opentelemetry-instrumentation-rack', '~> 0.24.1', require: false + gem 'opentelemetry-instrumentation-rails', '~> 0.30.0', require: false + gem 'opentelemetry-instrumentation-redis', '~> 0.25.3', require: false + gem 'opentelemetry-instrumentation-sidekiq', '~> 0.25.2', require: false + gem 'opentelemetry-sdk', '~> 1.4', require: false +end + group :test do # Adds RSpec Error/Warning annotations to GitHub PRs on the Files tab gem 'rspec-github', '~> 2.4', require: false diff --git a/Gemfile.lock b/Gemfile.lock index b4db2b9a07..b96afef2cc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -284,6 +284,9 @@ GEM ruby-progressbar (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) + google-protobuf (3.25.3) + googleapis-common-protos-types (1.14.0) + google-protobuf (~> 3.18) haml (6.3.0) temple (>= 0.8.2) thor @@ -483,6 +486,96 @@ GEM openssl (3.2.0) openssl-signature_algorithm (1.3.0) openssl (> 2.0) + opentelemetry-api (1.2.5) + opentelemetry-common (0.20.1) + opentelemetry-api (~> 1.0) + opentelemetry-exporter-otlp (0.26.3) + google-protobuf (~> 3.14) + googleapis-common-protos-types (~> 1.3) + opentelemetry-api (~> 1.1) + opentelemetry-common (~> 0.20) + opentelemetry-sdk (~> 1.2) + opentelemetry-semantic_conventions + opentelemetry-helpers-sql-obfuscation (0.1.0) + opentelemetry-common (~> 0.20) + opentelemetry-instrumentation-action_pack (0.9.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-rack (~> 0.21) + opentelemetry-instrumentation-action_view (0.7.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-active_support (~> 0.1) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-active_job (0.7.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-active_model_serializers (0.20.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-active_record (0.7.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-active_support (0.5.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-base (0.22.3) + opentelemetry-api (~> 1.0) + opentelemetry-registry (~> 0.1) + opentelemetry-instrumentation-concurrent_ruby (0.21.2) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-excon (0.22.0) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.20.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-faraday (0.24.1) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.20.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-http (0.23.2) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-http_client (0.22.3) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.20.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-net_http (0.22.4) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.20.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-pg (0.27.1) + opentelemetry-api (~> 1.0) + opentelemetry-helpers-sql-obfuscation + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-rack (0.24.1) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.20.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-rails (0.30.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-action_pack (~> 0.9.0) + opentelemetry-instrumentation-action_view (~> 0.7.0) + opentelemetry-instrumentation-active_job (~> 0.7.0) + opentelemetry-instrumentation-active_record (~> 0.7.0) + opentelemetry-instrumentation-active_support (~> 0.5.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-redis (0.25.3) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.20.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-instrumentation-sidekiq (0.25.2) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.20.0) + opentelemetry-instrumentation-base (~> 0.22.1) + opentelemetry-registry (0.3.1) + opentelemetry-api (~> 1.1) + opentelemetry-sdk (1.4.1) + opentelemetry-api (~> 1.1) + opentelemetry-common (~> 0.20) + opentelemetry-registry (~> 0.2) + opentelemetry-semantic_conventions + opentelemetry-semantic_conventions (1.10.0) + opentelemetry-api (~> 1.0) orm_adapter (0.5.0) ox (2.14.18) parallel (1.24.0) @@ -880,6 +973,21 @@ DEPENDENCIES omniauth-rails_csrf_protection (~> 1.0) omniauth-saml (~> 2.0) omniauth_openid_connect (~> 0.6.1) + opentelemetry-exporter-otlp (~> 0.26.3) + opentelemetry-instrumentation-active_job (~> 0.7.1) + opentelemetry-instrumentation-active_model_serializers (~> 0.20.1) + opentelemetry-instrumentation-concurrent_ruby (~> 0.21.2) + opentelemetry-instrumentation-excon (~> 0.22.0) + opentelemetry-instrumentation-faraday (~> 0.24.1) + opentelemetry-instrumentation-http (~> 0.23.2) + opentelemetry-instrumentation-http_client (~> 0.22.3) + opentelemetry-instrumentation-net_http (~> 0.22.4) + opentelemetry-instrumentation-pg (~> 0.27.1) + opentelemetry-instrumentation-rack (~> 0.24.1) + opentelemetry-instrumentation-rails (~> 0.30.0) + opentelemetry-instrumentation-redis (~> 0.25.3) + opentelemetry-instrumentation-sidekiq (~> 0.25.2) + opentelemetry-sdk (~> 1.4) ox (~> 2.14) parslet pg (~> 1.5) diff --git a/config/initializers/opentelemetry.rb b/config/initializers/opentelemetry.rb new file mode 100644 index 0000000000..e50132d461 --- /dev/null +++ b/config/initializers/opentelemetry.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +# Set OTEL_* environment variables according to OTel docs: +# https://opentelemetry.io/docs/concepts/sdk-configuration/ + +if ENV.keys.any? { |name| name.match?(/OTEL_.*_ENDPOINT/) } + require 'opentelemetry/sdk' + require 'opentelemetry/exporter/otlp' + + require 'opentelemetry/instrumentation/active_job' + require 'opentelemetry/instrumentation/active_model_serializers' + require 'opentelemetry/instrumentation/concurrent_ruby' + require 'opentelemetry/instrumentation/excon' + require 'opentelemetry/instrumentation/faraday' + require 'opentelemetry/instrumentation/http' + require 'opentelemetry/instrumentation/http_client' + require 'opentelemetry/instrumentation/net/http' + require 'opentelemetry/instrumentation/pg' + require 'opentelemetry/instrumentation/rack' + require 'opentelemetry/instrumentation/rails' + require 'opentelemetry/instrumentation/redis' + require 'opentelemetry/instrumentation/sidekiq' + + OpenTelemetry::SDK.configure do |c| + # use_all() attempts to load ALL the auto-instrumentations + # currently loaded by Ruby requires. + # + # Load attempts will emit an INFO or WARN to the console + # about the success/failure to wire up an auto-instrumentation. + # "WARN -- : Instrumentation: failed to install" is most + # likely caused by not being a Ruby library loaded by + # the application or the instrumentation has been explicitly + # disabled. + # + # To disable an instrumentation, set an environment variable + # along this pattern: + # + # OTEL_RUBY_INSTRUMENTATION__ENABLED=false + # + # For example, PostgreSQL and Redis produce a lot of child spans + # in the course of this application doing its business. To turn + # them off, set the env vars below, but recognize that you will + # be missing details about what particular calls to the + # datastores are slow. + # + # OTEL_RUBY_INSTRUMENTATION_PG_ENABLED=false + # OTEL_RUBY_INSTRUMENTATION_REDIS_ENABLED=false + + c.use_all({ + 'OpenTelemetry::Instrumentation::Rack' => { + use_rack_events: false, # instead of events, use middleware; allows for untraced_endpoints to ignore child spans + untraced_endpoints: ['/health'], + }, + }) + + c.service_name = case $PROGRAM_NAME + when /puma/ then 'mastodon/web' + else + "mastodon/#{$PROGRAM_NAME.split('/').last}" + end + c.service_version = Mastodon::Version.to_s + end +end From ded11eca4fe2d89d986663d6f6a8dd5284e4604a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 15:15:54 +0200 Subject: [PATCH 129/658] Update dependency pundit to v2.3.2 (#30222) 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 b96afef2cc..114abcb7b3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -607,7 +607,7 @@ GEM public_suffix (5.0.5) puma (6.4.2) nio4r (~> 2.0) - pundit (2.3.1) + pundit (2.3.2) activesupport (>= 3.0.0) raabro (1.4.0) racc (1.7.3) From d933e6b6aeda9fad6af712e084cdb5c25bdc2cbe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 15:16:02 +0200 Subject: [PATCH 130/658] Update dependency opentelemetry-instrumentation-concurrent_ruby to v0.21.3 (#30235) 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 114abcb7b3..3e2af23fec 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -521,7 +521,7 @@ GEM opentelemetry-instrumentation-base (0.22.3) opentelemetry-api (~> 1.0) opentelemetry-registry (~> 0.1) - opentelemetry-instrumentation-concurrent_ruby (0.21.2) + opentelemetry-instrumentation-concurrent_ruby (0.21.3) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) opentelemetry-instrumentation-excon (0.22.0) From af71f236a2e4565619871bfb72d64ca39411d365 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 15:16:05 +0200 Subject: [PATCH 131/658] Update dependency opentelemetry-instrumentation-excon to v0.22.2 (#30236) 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 3e2af23fec..fda00ca467 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -524,7 +524,7 @@ GEM opentelemetry-instrumentation-concurrent_ruby (0.21.3) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-excon (0.22.0) + opentelemetry-instrumentation-excon (0.22.1) opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) From 482d1087c57553f551cf495f62d9b7fccf649271 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 16:19:41 +0200 Subject: [PATCH 132/658] Update dependency opentelemetry-instrumentation-faraday to v0.24.3 (#30237) 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 fda00ca467..5669cf96a7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -528,7 +528,7 @@ GEM opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-faraday (0.24.1) + opentelemetry-instrumentation-faraday (0.24.2) opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) From d09b02efb653e59488cac530db8ae2757ad0cd02 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 10 May 2024 18:33:10 +0200 Subject: [PATCH 133/658] Group Ruby OTEL packages in Renovate PRs (#30242) --- .github/renovate.json5 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index e92608a437..378d4fc83c 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -141,6 +141,13 @@ matchUpdateTypes: ['patch', 'minor'], groupName: 'RSpec (non-major)', }, + { + // Group all opentelemetry-ruby packages in the same PR + matchManagers: ['bundler'], + matchPackagePrefixes: ['opentelemetry-'], + matchUpdateTypes: ['patch', 'minor'], + groupName: 'opentelemetry-ruby (non-major)', + }, // Add labels depending on package manager { matchManagers: ['npm', 'nvm'], addLabels: ['javascript'] }, { matchManagers: ['bundler', 'ruby-version'], addLabels: ['ruby'] }, From 9920f41c0fd8ad0030d2818c8271aa3cf24b4391 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 21:18:53 +0200 Subject: [PATCH 134/658] Update opentelemetry-ruby (non-major) (#30249) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5669cf96a7..3f4b1088ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -512,7 +512,7 @@ GEM opentelemetry-instrumentation-active_model_serializers (0.20.1) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-active_record (0.7.1) + opentelemetry-instrumentation-active_record (0.7.2) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) opentelemetry-instrumentation-active_support (0.5.1) @@ -532,10 +532,10 @@ GEM opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-http (0.23.2) + opentelemetry-instrumentation-http (0.23.3) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-http_client (0.22.3) + opentelemetry-instrumentation-http_client (0.22.4) opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) @@ -543,15 +543,15 @@ GEM opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-pg (0.27.1) + opentelemetry-instrumentation-pg (0.27.2) opentelemetry-api (~> 1.0) opentelemetry-helpers-sql-obfuscation opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-rack (0.24.1) + opentelemetry-instrumentation-rack (0.24.3) opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-rails (0.30.0) + opentelemetry-instrumentation-rails (0.30.1) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-action_pack (~> 0.9.0) opentelemetry-instrumentation-action_view (~> 0.7.0) @@ -559,11 +559,11 @@ GEM opentelemetry-instrumentation-active_record (~> 0.7.0) opentelemetry-instrumentation-active_support (~> 0.5.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-redis (0.25.3) + opentelemetry-instrumentation-redis (0.25.4) opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-sidekiq (0.25.2) + opentelemetry-instrumentation-sidekiq (0.25.3) opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) From 346530732cce54c3e690486aca256bc0aae26d17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 21:19:47 +0200 Subject: [PATCH 135/658] Update dependency utf-8-validate to v6.0.4 (#30248) 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 9aa8125d58..4f99844d64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17397,12 +17397,12 @@ __metadata: linkType: hard "utf-8-validate@npm:^6.0.3": - version: 6.0.3 - resolution: "utf-8-validate@npm:6.0.3" + version: 6.0.4 + resolution: "utf-8-validate@npm:6.0.4" dependencies: node-gyp: "npm:latest" node-gyp-build: "npm:^4.3.0" - checksum: 10c0/2ca08b07f4070540b33ff15f3f0632fa30baaee8a766fff993be47b4829b4fb30fd36fdf1270336324d03f65e0936c4608ee719d862230d75311751dcfe27a83 + checksum: 10c0/f7042d94aec6ca02461b64e725bdc7262266610dbb787331e5bbd49374ef6f75fe9900600df3fc63d97906c23614a965c8989b4bf95d70bf35dc617da99215e7 languageName: node linkType: hard From 1959365c2f410aa82874c5c05ab92c4eca4c4055 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 10 May 2024 22:00:25 +0200 Subject: [PATCH 136/658] Add missing `on_delete: :cascade` on `notification_policies` (#30251) --- ...3_fix_notification_policies_foreign_key.rb | 28 +++++++++++++++++++ db/schema.rb | 4 +-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240510192043_fix_notification_policies_foreign_key.rb diff --git a/db/migrate/20240510192043_fix_notification_policies_foreign_key.rb b/db/migrate/20240510192043_fix_notification_policies_foreign_key.rb new file mode 100644 index 0000000000..7bb134ecff --- /dev/null +++ b/db/migrate/20240510192043_fix_notification_policies_foreign_key.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class FixNotificationPoliciesForeignKey < ActiveRecord::Migration[7.1] + def up + safety_assured do + execute <<~SQL.squish + ALTER TABLE notification_policies + DROP CONSTRAINT fk_rails_506d62f0da, + ADD CONSTRAINT fk_rails_506d62f0da + FOREIGN KEY (account_id) + REFERENCES accounts(id) + ON DELETE CASCADE + SQL + end + end + + def down + safety_assured do + execute <<~SQL.squish + ALTER TABLE notification_policies + DROP CONSTRAINT fk_rails_506d62f0da, + ADD CONSTRAINT fk_rails_506d62f0da + FOREIGN KEY (account_id) + REFERENCES accounts(id) + SQL + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 11f1a202f7..ad58604928 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do +ActiveRecord::Schema[7.1].define(version: 2024_05_10_192043) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1335,7 +1335,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do add_foreign_key "mutes", "accounts", name: "fk_b8d8daf315", on_delete: :cascade add_foreign_key "notification_permissions", "accounts" add_foreign_key "notification_permissions", "accounts", column: "from_account_id" - add_foreign_key "notification_policies", "accounts" + add_foreign_key "notification_policies", "accounts", on_delete: :cascade add_foreign_key "notification_requests", "accounts", column: "from_account_id", on_delete: :cascade add_foreign_key "notification_requests", "accounts", on_delete: :cascade add_foreign_key "notification_requests", "statuses", column: "last_status_id", on_delete: :nullify From f65a6d50f1f9f48e50ea693c8b36dcb8dbb9f232 Mon Sep 17 00:00:00 2001 From: Chee Aun Date: Fri, 10 May 2024 17:19:27 +0800 Subject: [PATCH 137/658] [Glitch] Fix typo Port c36a8786c10c36e5181c9c53d848fa8e7b24b692 to glitch-soc Signed-off-by: Claire --- .../glitch/features/notifications/components/notification.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/flavours/glitch/features/notifications/components/notification.jsx b/app/javascript/flavours/glitch/features/notifications/components/notification.jsx index d03674bd57..29593c06d8 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/notification.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/notification.jsx @@ -31,7 +31,7 @@ const messages = defineMessages({ adminSignUp: { id: 'notification.admin.sign_up', defaultMessage: '{name} signed up' }, adminReport: { id: 'notification.admin.report', defaultMessage: '{name} reported {target}' }, relationshipsSevered: { id: 'notification.relationships_severance_event', defaultMessage: 'Lost connections with {name}' }, - moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'Your have received a moderation warning' }, + moderationWarning: { id: 'notification.moderation_warning', defaultMessage: 'You have received a moderation warning' }, }); const notificationForScreenReader = (intl, message, timestamp) => { From 807cf354fcf2706bd24890acb875fa85b097164a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 11:09:39 +0200 Subject: [PATCH 138/658] Update dependency eslint-plugin-jsdoc to v48.2.4 (#30274) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4f99844d64..f6166cccf9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2132,14 +2132,17 @@ __metadata: languageName: node linkType: hard -"@es-joy/jsdoccomment@npm:~0.42.0": - version: 0.42.0 - resolution: "@es-joy/jsdoccomment@npm:0.42.0" +"@es-joy/jsdoccomment@npm:~0.43.0": + version: 0.43.0 + resolution: "@es-joy/jsdoccomment@npm:0.43.0" dependencies: + "@types/eslint": "npm:^8.56.5" + "@types/estree": "npm:^1.0.5" + "@typescript-eslint/types": "npm:^7.2.0" comment-parser: "npm:1.4.1" esquery: "npm:^1.5.0" jsdoc-type-pratt-parser: "npm:~4.0.0" - checksum: 10c0/a8122762d2df3c6501a9c459e2822315a23c0078c4aeb0b40fb3c84b99e21a78e85e67f962d6b5dde5eb751792a1c67c6a170b619573db7151098a19950abe35 + checksum: 10c0/862294ed89772a231f309edd68405ece00f6aaf43103210f28410da894a6b697bc1f281c59e813dd37d5b7294f633ee7b874e07a0aa3d72f49504089fc9cb2c4 languageName: node linkType: hard @@ -3520,17 +3523,17 @@ __metadata: languageName: node linkType: hard -"@types/eslint@npm:7 || 8": - version: 8.44.6 - resolution: "@types/eslint@npm:8.44.6" +"@types/eslint@npm:7 || 8, @types/eslint@npm:^8.56.5": + version: 8.56.10 + resolution: "@types/eslint@npm:8.56.10" dependencies: "@types/estree": "npm:*" "@types/json-schema": "npm:*" - checksum: 10c0/fc449107eb186bdc5d30149bbcb4e673af8530afdeacca3b89f14deefcbfc67463157d6a81b42cd9df92ddeafda5351853d13310ff7ac6ab0d9769ac7cc0cc3a + checksum: 10c0/674349d6c342c3864d70f4d5a9965f96fb253801532752c8c500ad6a1c2e8b219e01ccff5dc8791dcb58b5483012c495708bb9f3ff929f5c9322b3da126c15d3 languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0": +"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5": version: 1.0.5 resolution: "@types/estree@npm:1.0.5" checksum: 10c0/b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d @@ -4193,7 +4196,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.8.0": +"@typescript-eslint/types@npm:7.8.0, @typescript-eslint/types@npm:^7.2.0": version: 7.8.0 resolution: "@typescript-eslint/types@npm:7.8.0" checksum: 10c0/b2fdbfc21957bfa46f7d8809b607ad8c8b67c51821d899064d09392edc12f28b2318a044f0cd5d523d782e84e8f0558778877944964cf38e139f88790cf9d466 @@ -7820,10 +7823,10 @@ __metadata: linkType: hard "eslint-plugin-jsdoc@npm:^48.0.0": - version: 48.2.3 - resolution: "eslint-plugin-jsdoc@npm:48.2.3" + version: 48.2.4 + resolution: "eslint-plugin-jsdoc@npm:48.2.4" dependencies: - "@es-joy/jsdoccomment": "npm:~0.42.0" + "@es-joy/jsdoccomment": "npm:~0.43.0" are-docs-informative: "npm:^0.0.2" comment-parser: "npm:1.4.1" debug: "npm:^4.3.4" @@ -7834,7 +7837,7 @@ __metadata: spdx-expression-parse: "npm:^4.0.0" peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: 10c0/e755923d96118890c6fd28b1c2298e1fe67ccbce08060ffc091b29ced59d0058ad8820323c56eef6f85c2954c783fc4076e78c0e5bc64838ae099b4e62ea702e + checksum: 10c0/601c9d6ee41de56102c7813106ceb0b8b8342223670f7add010a8f89753c250cde4cc93e353e3911b7b29677f2634f3f4be45f27abb7a95c6fdbd058adfa3343 languageName: node linkType: hard From ab4efa3bf89358a110f91af87055e1fc5d610d94 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 11:10:09 +0200 Subject: [PATCH 139/658] Update dependency @testing-library/react to v15.0.7 (#30273) 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 f6166cccf9..a7f8c0a61b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3391,8 +3391,8 @@ __metadata: linkType: hard "@testing-library/react@npm:^15.0.0": - version: 15.0.6 - resolution: "@testing-library/react@npm:15.0.6" + version: 15.0.7 + resolution: "@testing-library/react@npm:15.0.7" dependencies: "@babel/runtime": "npm:^7.12.5" "@testing-library/dom": "npm:^10.0.0" @@ -3404,7 +3404,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/3705a2272f929f2f848f5d7e6ac9829bf7ecc1725a35733ffae7e7a261d4bdab470b080558e8544edb1f9ba25db9fbc4232527df9b4ec6ab6ae4462a902a7f95 + checksum: 10c0/ac8ee8968e81949ecb35f7ee34741c2c043f73dd7fee2247d56f6de6a30de4742af94f25264356863974e54387485b46c9448ecf3f6ca41cf4339011c369f2d4 languageName: node linkType: hard From 471728d6ddb2bbc3579adde36942cbee622a3930 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 11:10:26 +0200 Subject: [PATCH 140/658] Update DefinitelyTyped types (non-major) (#30272) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index a7f8c0a61b..269ea79e88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3926,12 +3926,12 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7": - version: 18.3.1 - resolution: "@types/react@npm:18.3.1" + version: 18.3.2 + resolution: "@types/react@npm:18.3.2" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10c0/18d856c12a4ec93f3cda2d58ef3d77a9480818afd3af895f812896fb82cfca1f35a692ab1add4ce826a4eb58a071624c7d1c8c6c4ccfb81c100d2916dc607614 + checksum: 10c0/9fb2f1fcf7e889ee4ea7c3c5978df595c66e770e5fd3a245dbdd2589b9b911524c11dab25a6275d8af4e336e4cb5fa850d447884b84c335a187a338c89df99ba languageName: node linkType: hard @@ -4053,9 +4053,9 @@ __metadata: linkType: hard "@types/webpack-env@npm:^1.18.4": - version: 1.18.4 - resolution: "@types/webpack-env@npm:1.18.4" - checksum: 10c0/3fa77dbff0ed71685404576b0a1cf74587567fe2ee1cfd11d56d6eefcab7a61e4c9ead0eced264e289d2cf0fc74296dbd55ed6c95774fe0fd6264d156c5a59f0 + version: 1.18.5 + resolution: "@types/webpack-env@npm:1.18.5" + checksum: 10c0/b9e4876e8c7cae419896249f9ed795db283c008fe1d38efa679cbbf05194fc2eea2a5bfb4ff4393d109e3a9895416dadf5f3ddd5c22931b678062230f860454e languageName: node linkType: hard From 5e7d88a85d400423bb21986a6a6dbef0d89135c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 09:10:53 +0000 Subject: [PATCH 141/658] Update dependency glob to v10.3.15 (#30263) 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 269ea79e88..2ddd1a6426 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8885,8 +8885,8 @@ __metadata: linkType: hard "glob@npm:^10.2.2, glob@npm:^10.2.6, glob@npm:^10.3.10, glob@npm:^10.3.7": - version: 10.3.14 - resolution: "glob@npm:10.3.14" + version: 10.3.15 + resolution: "glob@npm:10.3.15" dependencies: foreground-child: "npm:^3.1.0" jackspeak: "npm:^2.3.6" @@ -8895,7 +8895,7 @@ __metadata: path-scurry: "npm:^1.11.0" bin: glob: dist/esm/bin.mjs - checksum: 10c0/19126e53b99c94dea9b3509500e22b325e24d2674523fc95b9fe710f1549ad7e091fbb0704c325c53d3a172fc21a8251acce5395c4f3efd872a2e65a376c82a1 + checksum: 10c0/cda748ddc181b31b3df9548c0991800406d5cc3b3f8110e37a8751ec1e39f37cdae7d7782d5422d7df92775121cdf00599992dff22f7ff1260344843af227c2b languageName: node linkType: hard From 123108b1ccf3e516be80f92f816def1ede77ee11 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 11:11:39 +0200 Subject: [PATCH 142/658] Update dependency postcss-preset-env to v9.5.12 (#30256) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 62 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2ddd1a6426..ed5c4fb33e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1617,15 +1617,15 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-cascade-layers@npm:^4.0.4": - version: 4.0.4 - resolution: "@csstools/postcss-cascade-layers@npm:4.0.4" +"@csstools/postcss-cascade-layers@npm:^4.0.5": + version: 4.0.5 + resolution: "@csstools/postcss-cascade-layers@npm:4.0.5" dependencies: - "@csstools/selector-specificity": "npm:^3.0.3" + "@csstools/selector-specificity": "npm:^3.1.0" postcss-selector-parser: "npm:^6.0.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/87fdd1e3d846e45c2e415f24f66076e04c3c4539e8b802f1114b2a0fef9421d562d9eb61464ba3599d73805555ad8e95c51a8827cb3ddacfda01ec0df4afbfe0 + checksum: 10c0/2b6dd33b51df349dd89b12ebe3240d65accb0ba03e40288a72e26cf2307a7bdd742c42d9ff7a3f886cab19b2f8813978075f6ee61a985b0b7ceac7e2cbb29e04 languageName: node linkType: hard @@ -1749,15 +1749,15 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-is-pseudo-class@npm:^4.0.6": - version: 4.0.6 - resolution: "@csstools/postcss-is-pseudo-class@npm:4.0.6" +"@csstools/postcss-is-pseudo-class@npm:^4.0.7": + version: 4.0.7 + resolution: "@csstools/postcss-is-pseudo-class@npm:4.0.7" dependencies: - "@csstools/selector-specificity": "npm:^3.0.3" + "@csstools/selector-specificity": "npm:^3.1.0" postcss-selector-parser: "npm:^6.0.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/aa071954e08dc9368fbeddbec6a8da2dea3a771b33bad53f67f3bc5a6b2f0a270909948f3e7b29ec885f4cceee245f16388809aeb0620284a1d66ad1f2026f28 + checksum: 10c0/43668987df4608f822dbc323d3ac567fa7c192235b55933fd5d1855977ead80184512eb64a3f45a020fdd93711952ba8e9f9a280f4e981625b68a9ff074f9a01 languageName: node linkType: hard @@ -1983,12 +1983,12 @@ __metadata: languageName: node linkType: hard -"@csstools/selector-specificity@npm:^3.0.3": - version: 3.0.3 - resolution: "@csstools/selector-specificity@npm:3.0.3" +"@csstools/selector-specificity@npm:^3.0.3, @csstools/selector-specificity@npm:^3.1.0": + version: 3.1.0 + resolution: "@csstools/selector-specificity@npm:3.1.0" peerDependencies: postcss-selector-parser: ^6.0.13 - checksum: 10c0/e4f0355165882ddde8bd4a2f0252868150e67b9fae927fd2d94a91cee31e438e7041059f20b9c755a93b0bd8e527a9f78b01168fe67b3539be32091240aa63bf + checksum: 10c0/7f77f8377b637dcca7f7a9d6ace3329cf60f02cbd75f14241de30b1f5d00c961ec167572bc93517cdb2f106405a91119f026389a0f96dabae8dd67d1c7710e60 languageName: node linkType: hard @@ -6577,16 +6577,16 @@ __metadata: languageName: node linkType: hard -"css-has-pseudo@npm:^6.0.3": - version: 6.0.3 - resolution: "css-has-pseudo@npm:6.0.3" +"css-has-pseudo@npm:^6.0.4": + version: 6.0.4 + resolution: "css-has-pseudo@npm:6.0.4" dependencies: - "@csstools/selector-specificity": "npm:^3.0.3" + "@csstools/selector-specificity": "npm:^3.1.0" postcss-selector-parser: "npm:^6.0.13" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/bbe663eff5256233c7bcce256cd8de7d93d82f2d4f2ca104af8e39e2159170d67746d3a2954385d03ec4ea7ef2728fe9a7d8cb62c52c0a6df1ad3d3bb1e3439d + checksum: 10c0/e9d440de483e15092ebaadb483502243f43e0457d4214c8012ebdba7a959e74d40714254bf97247780e65735512f248a55feda0b3975d9a5eaea9c746f7518f0 languageName: node linkType: hard @@ -13548,16 +13548,16 @@ __metadata: languageName: node linkType: hard -"postcss-nesting@npm:^12.1.2": - version: 12.1.2 - resolution: "postcss-nesting@npm:12.1.2" +"postcss-nesting@npm:^12.1.3": + version: 12.1.3 + resolution: "postcss-nesting@npm:12.1.3" dependencies: "@csstools/selector-resolve-nested": "npm:^1.1.0" - "@csstools/selector-specificity": "npm:^3.0.3" + "@csstools/selector-specificity": "npm:^3.1.0" postcss-selector-parser: "npm:^6.0.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/39d1d100f61863f904393b17169be83cdf82bd50d530efb3e3ae0c7b0f838b254e10e5d12e25119cf31dce9e351a2b770a03f9b2029ff33bef0ec924c0d2f642 + checksum: 10c0/6b2d3a4823e85592965c6c11f749c5357703256e7334388147d6a3bb72a3abbe47789afaa8535bdd7a9bd6d0099eb12ffec6c154050d8e8b8286b1adbed5b397 languageName: node linkType: hard @@ -13712,10 +13712,10 @@ __metadata: linkType: hard "postcss-preset-env@npm:^9.5.2": - version: 9.5.11 - resolution: "postcss-preset-env@npm:9.5.11" + version: 9.5.12 + resolution: "postcss-preset-env@npm:9.5.12" dependencies: - "@csstools/postcss-cascade-layers": "npm:^4.0.4" + "@csstools/postcss-cascade-layers": "npm:^4.0.5" "@csstools/postcss-color-function": "npm:^3.0.16" "@csstools/postcss-color-mix-function": "npm:^2.0.16" "@csstools/postcss-exponential-functions": "npm:^1.0.7" @@ -13725,7 +13725,7 @@ __metadata: "@csstools/postcss-hwb-function": "npm:^3.0.15" "@csstools/postcss-ic-unit": "npm:^3.0.6" "@csstools/postcss-initial": "npm:^1.0.1" - "@csstools/postcss-is-pseudo-class": "npm:^4.0.6" + "@csstools/postcss-is-pseudo-class": "npm:^4.0.7" "@csstools/postcss-light-dark-function": "npm:^1.0.5" "@csstools/postcss-logical-float-and-clear": "npm:^2.0.1" "@csstools/postcss-logical-overflow": "npm:^1.0.1" @@ -13747,7 +13747,7 @@ __metadata: autoprefixer: "npm:^10.4.19" browserslist: "npm:^4.22.3" css-blank-pseudo: "npm:^6.0.2" - css-has-pseudo: "npm:^6.0.3" + css-has-pseudo: "npm:^6.0.4" css-prefers-color-scheme: "npm:^9.0.1" cssdb: "npm:^8.0.0" postcss-attribute-case-insensitive: "npm:^6.0.3" @@ -13767,7 +13767,7 @@ __metadata: postcss-image-set-function: "npm:^6.0.3" postcss-lab-function: "npm:^6.0.16" postcss-logical: "npm:^7.0.1" - postcss-nesting: "npm:^12.1.2" + postcss-nesting: "npm:^12.1.3" postcss-opacity-percentage: "npm:^2.0.0" postcss-overflow-shorthand: "npm:^5.0.1" postcss-page-break: "npm:^3.0.4" @@ -13777,7 +13777,7 @@ __metadata: postcss-selector-not: "npm:^7.0.2" peerDependencies: postcss: ^8.4 - checksum: 10c0/9460f4ce18cf1af7582d0a1f366151f59b6e9b0c7cbb62e59081dc91da14760a749f59fa52bc190e5e2c8fd531952c647719d19c4740aa1a0ebcb93f075ad931 + checksum: 10c0/3e0276b2061baa396547f9c0090fcb0c6149d3735c7aefa99a8e520701aae0b7265578b59d5e4efa9f5e61659c161e39590a5d63bac49469b99da1c549b63231 languageName: node linkType: hard From f66c9faca02018a3aa6140506a15d685b89dfed2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 11:11:55 +0200 Subject: [PATCH 143/658] Update dependency sass to v1.77.1 (#30252) 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 ed5c4fb33e..f2d2906537 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15323,15 +15323,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.77.0 - resolution: "sass@npm:1.77.0" + version: 1.77.1 + resolution: "sass@npm:1.77.1" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/bce0e5f5b535491e4e775045a79f19cbe10d800ef53b5f7698958d2992505d7b124c968169b05a0190842d8e0a24c2aa6d75dfbdd7c213820d9d59e227009c19 + checksum: 10c0/edcfc7d038234b1198c3ddcac5963fcd1e17a9c1ee0f9bd09784ab5353b60ff50b189b4c9154b34f5da9ca0eaab8b189fd3e83a4b43a494151ad4735f8e5f364 languageName: node linkType: hard From cb93c1edf08865b1ac528a9a4cb747dab3d57e8d Mon Sep 17 00:00:00 2001 From: David Lapshin Date: Mon, 13 May 2024 12:19:42 +0300 Subject: [PATCH 144/658] Add active animation to header settings button (#30221) --- app/javascript/styles/mastodon/components.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 12c987a02f..927c57d990 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -4365,12 +4365,20 @@ a.status-card { outline: $ui-button-focus-outline; } + .no-reduce-motion .icon { + transition: transform 0.15s ease-in-out; + } + &.active { color: $primary-text-color; &:hover { color: $primary-text-color; } + + .icon { + transform: rotate(60deg); + } } &:disabled { From c66fdb3dff7f9313ff610a6b6e97ee22e3b3c7e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 11:39:06 +0200 Subject: [PATCH 145/658] Update dependency immutable to v4.3.6 (#30276) 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 f2d2906537..f6dc8f161a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9495,9 +9495,9 @@ __metadata: linkType: hard "immutable@npm:^4.0.0, immutable@npm:^4.0.0-rc.1, immutable@npm:^4.3.0": - version: 4.3.5 - resolution: "immutable@npm:4.3.5" - checksum: 10c0/63d2d7908241a955d18c7822fd2215b6e89ff5a1a33cc72cd475b013cbbdef7a705aa5170a51ce9f84a57f62fdddfaa34e7b5a14b33d8a43c65cc6a881d6e894 + version: 4.3.6 + resolution: "immutable@npm:4.3.6" + checksum: 10c0/7d0952a768b4fadcee47230ed86dc9505a4517095eceaf5a47e65288571c42400c6e4a2ae21eca4eda957cb7bc50720213135b62cf6a181639111f8acae128c3 languageName: node linkType: hard From b429c9b8a7848097a1c86edda465629a11267696 Mon Sep 17 00:00:00 2001 From: Jeen Broekstra Date: Mon, 13 May 2024 21:40:14 +1200 Subject: [PATCH 146/658] fix(bin/dev): makes conditional for launching overmind POSIX-compliant (#30271) --- bin/dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/dev b/bin/dev index 9b1d3ac6fc..0911bae558 100755 --- a/bin/dev +++ b/bin/dev @@ -6,7 +6,7 @@ export PORT="${PORT:-3000}" # Get around our boot.rb ENV check export RAILS_ENV="${RAILS_ENV:-development}" -if command -v overmind &> /dev/null +if command -v overmind 1> /dev/null 2>&1 then overmind start -f Procfile.dev "$@" exit $? From 6e1b8b33f55de9fdfcd4ce3a8fcc965c1b5c6601 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 11:42:08 +0200 Subject: [PATCH 147/658] Update opentelemetry-ruby (non-major) (#30262) 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 3f4b1088ad..efc99eb23d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -543,7 +543,7 @@ GEM opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-pg (0.27.2) + opentelemetry-instrumentation-pg (0.27.3) opentelemetry-api (~> 1.0) opentelemetry-helpers-sql-obfuscation opentelemetry-instrumentation-base (~> 0.22.1) From 9ec7c1f89256cf3c658a67c3cf8b956fd4dab265 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Mon, 13 May 2024 05:42:47 -0400 Subject: [PATCH 148/658] Fix i18n:extract flags (#30261) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d884883331..79544229df 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "fix": "yarn fix:js && yarn fix:css", "format": "prettier --write --log-level warn .", "format:check": "prettier --check --ignore-unknown .", - "i18n:extract": "formatjs extract 'app/javascript/**/*.{js,jsx,ts,tsx}' '--ignore=**/*.d.ts' --out-file app/javascript/mastodon/locales/en.json --format config/formatjs-formatter.js", + "i18n:extract": "formatjs extract 'app/javascript/**/*.{js,jsx,ts,tsx}' --ignore '**/*.d.ts' --out-file app/javascript/mastodon/locales/en.json --format config/formatjs-formatter.js", "jest": "cross-env NODE_ENV=test jest", "lint:js": "eslint . --ext=.js,.jsx,.ts,.tsx --cache --report-unused-disable-directives", "lint:css": "stylelint \"**/*.{css,scss}\"", From 13fb54920b1c1e8dd59798dd9fc3466c5a446898 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Mon, 13 May 2024 05:54:15 -0400 Subject: [PATCH 149/658] Enable Style/IfUnlessModifier RuboCop (#30260) --- .rubocop_todo.yml | 9 +-------- config/environments/production.rb | 4 +--- config/initializers/devise.rb | 4 +--- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 91e666d7f4..b47d682f3e 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp` -# using RuboCop version 1.62.1. +# using RuboCop version 1.63.5. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -122,13 +122,6 @@ Style/HashTransformValues: - 'app/serializers/rest/web_push_subscription_serializer.rb' - 'app/services/import_service.rb' -# This cop supports safe autocorrection (--autocorrect). -Style/IfUnlessModifier: - Exclude: - - 'config/environments/production.rb' - - 'config/initializers/devise.rb' - - 'config/initializers/ffmpeg.rb' - # This cop supports unsafe autocorrection (--autocorrect-all). Style/MapToHash: Exclude: diff --git a/config/environments/production.rb b/config/environments/production.rb index 6b1101ea1b..a39843e956 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -86,9 +86,7 @@ Rails.application.configure do config.lograge.enabled = true config.lograge.custom_payload do |controller| - if controller.respond_to?(:signed_request?) && controller.signed_request? - { key: controller.signature_key_id } - end + { key: controller.signature_key_id } if controller.respond_to?(:signed_request?) && controller.signed_request? end # Use a different logger for distributed setups. diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index a95c7437fa..5c88c4cd5f 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -79,9 +79,7 @@ module Devise return pass end - if validate(resource) - success!(resource) - end + success!(resource) if validate(resource) end private From 3a7aec2807089a004db90851c66db0a007a18a48 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 13:30:41 +0200 Subject: [PATCH 150/658] New Crowdin Translations (automated) (#30254) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/cy.json | 1 - app/javascript/mastodon/locales/es-MX.json | 6 +- app/javascript/mastodon/locales/es.json | 6 +- app/javascript/mastodon/locales/fo.json | 4 +- app/javascript/mastodon/locales/gl.json | 1 - app/javascript/mastodon/locales/ia.json | 2 +- app/javascript/mastodon/locales/ie.json | 4 + app/javascript/mastodon/locales/ja.json | 2 +- app/javascript/mastodon/locales/lt.json | 5 +- app/javascript/mastodon/locales/pt-BR.json | 1 - app/javascript/mastodon/locales/sl.json | 1 - app/javascript/mastodon/locales/sq.json | 2 +- app/javascript/mastodon/locales/sv.json | 2 +- app/javascript/mastodon/locales/vi.json | 2 +- app/javascript/mastodon/locales/zh-HK.json | 1 - config/locales/doorkeeper.vi.yml | 4 +- config/locales/fo.yml | 4 +- config/locales/ia.yml | 106 +++++++++++++++++++++ config/locales/ie.yml | 3 + config/locales/lt.yml | 53 ++++++++++- config/locales/simple_form.cs.yml | 2 + config/locales/simple_form.es-MX.yml | 2 + config/locales/simple_form.es.yml | 2 + config/locales/simple_form.ie.yml | 6 ++ config/locales/simple_form.ja.yml | 2 + config/locales/simple_form.ko.yml | 3 + config/locales/simple_form.lt.yml | 5 + config/locales/th.yml | 3 + 28 files changed, 208 insertions(+), 27 deletions(-) diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index fd8fc74be8..925b7710e0 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -474,7 +474,6 @@ "notification.follow_request": "Mae {name} wedi gwneud cais i'ch dilyn", "notification.mention": "Crybwyllodd {name} amdanoch chi", "notification.moderation-warning.learn_more": "Dysgu mwy", - "notification.moderation_warning": "Rydych wedi derbyn rhybudd cymedroli", "notification.moderation_warning.action_delete_statuses": "Mae rhai o'ch postiadau wedi'u dileu.", "notification.moderation_warning.action_disable": "Mae eich cyfrif wedi'i analluogi.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Mae rhai o'ch postiadau wedi'u marcio'n sensitif.", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index b529f48ebe..1a99d1d4b4 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -476,12 +476,12 @@ "notification.moderation-warning.learn_more": "Saber más", "notification.moderation_warning": "Has recibido una advertencia de moderación", "notification.moderation_warning.action_delete_statuses": "Se han eliminado algunas de tus publicaciones.", - "notification.moderation_warning.action_disable": "Se ha desactivado su cuenta.", + "notification.moderation_warning.action_disable": "Tu cuenta ha sido desactivada.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Se han marcado como sensibles algunas de tus publicaciones.", "notification.moderation_warning.action_none": "Tu cuenta ha recibido un aviso de moderación.", "notification.moderation_warning.action_sensitive": "De ahora en adelante, todas tus publicaciones se marcarán como sensibles.", - "notification.moderation_warning.action_silence": "Se ha limitado tu cuenta.", - "notification.moderation_warning.action_suspend": "Se ha suspendido tu cuenta.", + "notification.moderation_warning.action_silence": "Tu cuenta ha sido limitada.", + "notification.moderation_warning.action_suspend": "Tu cuenta ha sido suspendida.", "notification.own_poll": "Tu encuesta ha terminado", "notification.poll": "Una encuesta en la que has votado ha terminado", "notification.reblog": "{name} ha retooteado tu estado", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index ed01a33375..1782a3a1fe 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -476,12 +476,12 @@ "notification.moderation-warning.learn_more": "Saber más", "notification.moderation_warning": "Has recibido una advertencia de moderación", "notification.moderation_warning.action_delete_statuses": "Se han eliminado algunas de tus publicaciones.", - "notification.moderation_warning.action_disable": "Se ha desactivado su cuenta.", + "notification.moderation_warning.action_disable": "Tu cuenta ha sido desactivada.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Se han marcado como sensibles algunas de tus publicaciones.", "notification.moderation_warning.action_none": "Tu cuenta ha recibido un aviso de moderación.", "notification.moderation_warning.action_sensitive": "De ahora en adelante, todas tus publicaciones se marcarán como sensibles.", - "notification.moderation_warning.action_silence": "Se ha limitado tu cuenta.", - "notification.moderation_warning.action_suspend": "Se ha suspendido tu cuenta.", + "notification.moderation_warning.action_silence": "Tu cuenta ha sido limitada.", + "notification.moderation_warning.action_suspend": "Tu cuenta ha sido suspendida.", "notification.own_poll": "Tu encuesta ha terminado", "notification.poll": "Una encuesta en la que has votado ha terminado", "notification.reblog": "{name} ha impulsado tu publicación", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 77257413fd..f22a829c0c 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -474,11 +474,11 @@ "notification.follow_request": "{name} biður um at fylgja tær", "notification.mention": "{name} nevndi teg", "notification.moderation-warning.learn_more": "Lær meira", - "notification.moderation_warning": "Tú hevur móttikið eina umsjónarávarðing", + "notification.moderation_warning": "Tú hevur móttikið eina umsjónarávaring", "notification.moderation_warning.action_delete_statuses": "Onkrir av tínum postum eru strikaðir.", "notification.moderation_warning.action_disable": "Konta tín er gjørd óvirkin.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nakrir av postum tínum eru merktir sum viðkvæmir.", - "notification.moderation_warning.action_none": "Konta tín hevur móttikið eina umsjónarávarðing.", + "notification.moderation_warning.action_none": "Konta tín hevur móttikið eina umsjónarávaring.", "notification.moderation_warning.action_sensitive": "Postar tínir verða merktir sum viðkvæmir frá nú av.", "notification.moderation_warning.action_silence": "Konta tín er avmarkað.", "notification.moderation_warning.action_suspend": "Konta tín er ógildað.", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 88d4f5f60e..b2a50ebb81 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -474,7 +474,6 @@ "notification.follow_request": "{name} solicitou seguirte", "notification.mention": "{name} mencionoute", "notification.moderation-warning.learn_more": "Saber máis", - "notification.moderation_warning": "Recibiches unha advertencia da moderación", "notification.moderation_warning.action_delete_statuses": "Algunha das túas publicacións foron eliminadas.", "notification.moderation_warning.action_disable": "A túa conta foi desactivada.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algunha das túas publicacións foron marcadas como sensibles.", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index d30038d9cc..313563bdfe 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -474,7 +474,7 @@ "notification.follow_request": "{name} ha requestate de sequer te", "notification.mention": "{name} te ha mentionate", "notification.moderation-warning.learn_more": "Apprender plus", - "notification.moderation_warning": "Tu ha recipite un advertimento de moderation", + "notification.moderation_warning": "Tu ha recepite un aviso de moderation", "notification.moderation_warning.action_delete_statuses": "Alcunes de tu messages ha essite removite.", "notification.moderation_warning.action_disable": "Tu conto ha essite disactivate.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Alcunes de tu messages ha essite marcate como sensibile.", diff --git a/app/javascript/mastodon/locales/ie.json b/app/javascript/mastodon/locales/ie.json index 7bd91ca0f9..1921509478 100644 --- a/app/javascript/mastodon/locales/ie.json +++ b/app/javascript/mastodon/locales/ie.json @@ -89,6 +89,7 @@ "announcement.announcement": "Proclamation", "attachments_list.unprocessed": "(íntractat)", "audio.hide": "Celar audio", + "block_modal.remote_users_caveat": "Noi va petir que li servitor {domain} mey respecter tui decision. Támen, obedientie ne es garantit pro que chascun servitor gere bloccas diferentmen. Possibilmen public postas va restar visibil a usatores de inloggat.", "block_modal.show_less": "Monstrar minu", "block_modal.show_more": "Monstrar plu", "block_modal.they_cant_mention": "Ne posse mentionar ni sequer te.", @@ -224,7 +225,10 @@ "domain_pill.their_username": "Su unic identificator sur su servitor. It es possibil que altri servitores va haver usatores con li sam nómine.", "domain_pill.username": "Usator-nómine", "domain_pill.whats_in_a_handle": "Ex quo consiste un identificator?", + "domain_pill.who_they_are": "Pro que identificatores informa qui e u un person is, tu posse interacter con persones tra li rete social de .", + "domain_pill.who_you_are": "Pro que tui identificator informa qui e u tu es, persones posse interacter con te tra li rete social de .", "domain_pill.your_handle": "Tui identificator:", + "domain_pill.your_server": "Tui digital hem, u trova se omni tui postas. Si it ne plese te, tu posse transferer ad un altri servitor quandecunc e tui sequitores con te.", "domain_pill.your_username": "Tui unic identificator sur ti-ci servitor. It es possibil que altri servitores va haver usatores con li sam nómine.", "embed.instructions": "Inbedar ti-ci posta per copiar li code in infra.", "embed.preview": "Vi qualmen it va aspecter:", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 6e590678fb..eea06fff59 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -474,7 +474,7 @@ "notification.follow_request": "{name}さんがあなたにフォローリクエストしました", "notification.mention": "{name}さんがあなたに返信しました", "notification.moderation-warning.learn_more": "さらに詳しく", - "notification.moderation_warning": "あなたは管理者からの警告を受けています。", + "notification.moderation_warning": "管理者から警告が来ています", "notification.moderation_warning.action_delete_statuses": "あなたによるいくつかの投稿が削除されました。", "notification.moderation_warning.action_disable": "あなたのアカウントは無効になりました。", "notification.moderation_warning.action_mark_statuses_as_sensitive": "あなたの投稿のいくつかは閲覧注意として判定されています。", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 798b24569f..0f42e97fcf 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -256,7 +256,7 @@ "empty_column.community": "Vietinė laiko skalė yra tuščia. Parašyk ką nors viešai, kad pradėtum sąveikauti.", "empty_column.direct": "Dar neturi jokių privačių paminėjimų. Kai išsiųsi arba gausi vieną iš jų, jis bus rodomas čia.", "empty_column.domain_blocks": "Dar nėra užblokuotų domenų.", - "empty_column.explore_statuses": "Šiuo metu niekas nėra tendencinga. Patikrink vėliau.", + "empty_column.explore_statuses": "Šiuo metu niekas nėra tendencinga. Patikrink vėliau!", "empty_column.favourited_statuses": "Dar neturi mėgstamų įrašų. Kai vieną iš jų pamėgsi, jis bus rodomas čia.", "empty_column.favourites": "Šio įrašo dar niekas nepamėgo. Kai kas nors tai padarys, jie bus rodomi čia.", "empty_column.follow_requests": "Dar neturi jokių sekimo prašymų. Kai gausi tokį prašymą, jis bus rodomas čia.", @@ -466,7 +466,6 @@ "notification.follow_request": "{name} paprašė tave sekti", "notification.mention": "{name} paminėjo tave", "notification.moderation-warning.learn_more": "Sužinoti daugiau", - "notification.moderation_warning": "Gavai prižiūrėjimo įspėjimą", "notification.moderation_warning.action_delete_statuses": "Kai kurie tavo įrašai buvo pašalintos.", "notification.moderation_warning.action_disable": "Tavo paskyra buvo išjungta.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Kai kurie tavo įrašai buvo pažymėtos kaip jautrios.", @@ -536,7 +535,7 @@ "onboarding.follows.lead": "Tavo pagrindinis srautas – pagrindinis būdas patirti Mastodon. Kuo daugiau žmonių seksi, tuo jis bus aktyvesnis ir įdomesnis. Norint pradėti, pateikiame keletą pasiūlymų:", "onboarding.follows.title": "Suasmenink savo pagrindinį srautą", "onboarding.profile.discoverable": "Padaryti mano profilį atrandamą", - "onboarding.profile.discoverable_hint": "Kai pasirenki Mastodon atrandamumą, tavo įrašai gali būti rodomi paieškos rezultatuose ir tendencijose, o profilis gali būti siūlomas panašių pomėgių turintiems žmonėms.", + "onboarding.profile.discoverable_hint": "Kai sutinki su Mastodon atrandamumu, tavo įrašai gali būti rodomi paieškos rezultatuose ir tendencijose, o profilis gali būti siūlomas panašių pomėgių turintiems žmonėms.", "onboarding.profile.display_name": "Rodomas vardas", "onboarding.profile.display_name_hint": "Tavo pilnas vardas arba linksmas vardas…", "onboarding.profile.lead": "Gali visada tai užbaigti vėliau nustatymuose, kur yra dar daugiau pritaikymo parinkčių.", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index b11daeaaa7..1a6de08359 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -474,7 +474,6 @@ "notification.follow_request": "{name} quer te seguir", "notification.mention": "{name} te mencionou", "notification.moderation-warning.learn_more": "Aprender mais", - "notification.moderation_warning": "Você recebeu um aviso de moderação", "notification.moderation_warning.action_delete_statuses": "Algumas das suas publicações foram removidas.", "notification.moderation_warning.action_disable": "Sua conta foi desativada.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algumas de suas publicações foram marcadas por ter conteúdo sensível.", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 7806abc6b5..459d05ce3e 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -474,7 +474,6 @@ "notification.follow_request": "{name} vam želi slediti", "notification.mention": "{name} vas je omenil/a", "notification.moderation-warning.learn_more": "Več o tem", - "notification.moderation_warning": "Prejeli ste opozorilo moderatorjev", "notification.moderation_warning.action_delete_statuses": "Nekatere vaše objave so odstranjene.", "notification.moderation_warning.action_disable": "Vaš račun je bil onemogočen.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nekatere vaše objave so bile označene kot občutljive.", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index a25eab9cbf..b496f8e203 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -474,7 +474,7 @@ "notification.follow_request": "{name} ka kërkuar t’ju ndjekë", "notification.mention": "{name} ju ka përmendur", "notification.moderation-warning.learn_more": "Mësoni më tepër", - "notification.moderation_warning": "Keni marrë një sinjalizim moderimi", + "notification.moderation_warning": "Ju është dhënë një sinjalizim moderimi", "notification.moderation_warning.action_delete_statuses": "Disa nga postimet tuaja janë hequr.", "notification.moderation_warning.action_disable": "Llogaria juaj është çaktivizuar.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Disa prej postimeve tuaja u është vënë shenjë si me spec.", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 5ac4b4648f..ba3a6b2f51 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -474,7 +474,7 @@ "notification.follow_request": "{name} har begärt att följa dig", "notification.mention": "{name} nämnde dig", "notification.moderation-warning.learn_more": "Läs mer", - "notification.moderation_warning": "Du har mottagit en modereringsvarning", + "notification.moderation_warning": "Du har fått en moderationsvarning", "notification.moderation_warning.action_delete_statuses": "Några av dina inlägg har tagits bort.", "notification.moderation_warning.action_disable": "Ditt konto har inaktiverats.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Några av dina inlägg har markerats som känsliga.", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index b188488f0b..102f1c3b4b 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -474,7 +474,7 @@ "notification.follow_request": "{name} yêu cầu theo dõi bạn", "notification.mention": "{name} nhắc đến bạn", "notification.moderation-warning.learn_more": "Tìm hiểu", - "notification.moderation_warning": "Bạn đã nhận một cảnh báo kiểm duyệt", + "notification.moderation_warning": "Bạn vừa nhận một cảnh báo kiểm duyệt", "notification.moderation_warning.action_delete_statuses": "Một vài tút của bạn bị gỡ.", "notification.moderation_warning.action_disable": "Tài khoản của bạn đã bị vô hiệu hóa.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Vài tút bạn bị đánh dấu nhạy cảm.", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 6b08e40284..eaa5dabe93 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -474,7 +474,6 @@ "notification.follow_request": "{name} 要求追蹤你", "notification.mention": "{name} 提及你", "notification.moderation-warning.learn_more": "了解更多", - "notification.moderation_warning": "你收到一則審核警告", "notification.moderation_warning.action_delete_statuses": "你的部份帖文已被刪除。", "notification.moderation_warning.action_disable": "你的帳號已被停用。", "notification.moderation_warning.action_mark_statuses_as_sensitive": "你某些帖文已被標記為敏感內容。", diff --git a/config/locales/doorkeeper.vi.yml b/config/locales/doorkeeper.vi.yml index 84684d24ca..624db9aff7 100644 --- a/config/locales/doorkeeper.vi.yml +++ b/config/locales/doorkeeper.vi.yml @@ -61,7 +61,7 @@ vi: title: Một lỗi đã xảy ra new: prompt_html: "%{client_name} yêu cầu truy cập tài khoản của bạn. Đây là ứng dụng của bên thứ ba. Nếu không tin tưởng, đừng cho phép nó." - review_permissions: Xem lại quyền cho phép + review_permissions: Quyền truy cập title: Yêu cầu truy cập show: title: Sao chép mã này và dán nó vào ứng dụng. @@ -122,7 +122,7 @@ vi: admin/accounts: Quản trị tài khoản admin/all: Mọi chức năng quản trị admin/reports: Quản trị báo cáo - all: Toàn quyền truy cập vào tài khoản Mastodon của bạn + all: Toàn quyền truy cập tài khoản Mastodon blocks: Chặn bookmarks: Tút đã lưu conversations: Thảo luận diff --git a/config/locales/fo.yml b/config/locales/fo.yml index 15c9c7dc04..f7303c512a 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -235,7 +235,7 @@ fo: change_email_user_html: "%{name} broytti teldupost addressuna hjá %{target}" change_role_user_html: "%{name} broytti leiklutin hjá %{target}" confirm_user_html: "%{name} góðtók teldupost addressuna hjá %{target}" - create_account_warning_html: "%{name} sendi eina ávarðing til %{target}" + create_account_warning_html: "%{name} sendi eina ávaring til %{target}" create_announcement_html: "%{name} stovnaði eina fráboðan %{target}" create_canonical_email_block_html: "%{name} forðaði telduposti við hash'inum %{target}" create_custom_emoji_html: "%{name} legði upp nýtt kenslutekn %{target}" @@ -1835,7 +1835,7 @@ fo: delete_statuses: Summir av postum tínum eru staðfestir at vera í stríði við eina ella fleiri av leiðreglunum og eru tí strikaðir av umsjónarfólkunum á %{instance}. disable: Tú kanst ikki longur brúka tína kontu, men vangi tín og aðrar dátur eru óskalað. Tú kanst biðja um trygdaravrit av tínum dátum, broyta kontustillingar ella strika tína kontu. mark_statuses_as_sensitive: Summir av postum tínum eru merktir sum viðkvæmir av umsjónarfólkunum á %{instance}. Hetta merkir, at fólk mugu trýsta á miðilin í postinum, áðrenn ein undanvísing verður víst. Tú kanst sjálv/ur merkja miðlar viðkvæmar, tá tú postar í framtíðini. - sensitive: Frá nú av, so verða allar miðlafílur, sum tú leggur upp, merktar sum viðkvæmar og fjaldar aftan fyri eina ávarðing. + sensitive: Frá nú av, so verða allar miðlafílur, sum tú leggur upp, merktar sum viðkvæmar og fjaldar aftan fyri eina ávaring. silence: Tú kanst framvegis brúka kontu tína, men einans fólk, sum longu fylgja tær, fara at síggja tínar postar á hesum ambætaranum, og tú kanst vera hildin uttanfyri ymiskar leitihentleikar. Tó so, onnur kunnu framvegis fylgja tær beinleiðis. suspend: Tú kanst ikki longur brúka kontu tína og vangin og aðrar dátur eru ikki longur atkomulig. Tú kanst enn rita inn fyri at biðja um eitt trygdaravrit av tínum dátum, inntil dáturnar eru heilt burturbeindar um umleið 30 dagar, men vit varðveita nakrar grundleggjandi dátur fyri at forða tær í at støkka undan ógildingini. reason: 'Grund:' diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 712328deb8..46cdcd3c68 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -350,6 +350,18 @@ ia: media_storage: Immagazinage de medios new_users: nove usatores opened_reports: reportos aperte + pending_appeals_html: + one: "%{count} appello pendente" + other: "%{count} appellos pendente" + pending_reports_html: + one: "%{count} reporto pendente" + other: "%{count} reportos pendente" + pending_tags_html: + one: "%{count} hashtag pendente" + other: "%{count} hashtags pendente" + pending_users_html: + one: "%{count} usator pendente" + other: "%{count} usatores pendente" resolved_reports: reportos resolvite software: Software sources: Fontes de inscription @@ -972,21 +984,40 @@ ia: silence: pro limitar lor conto suspend: pro suspender lor conto body: "%{target} appella un decision de moderation per %{action_taken_by} ab le %{date}, que era %{type}. Ille scribeva:" + next_steps: Tu pote approbar le appello a disfacer le decision de moderation, o ignorar lo. + subject: "%{username} appella un decision de moderation sur %{instance}" new_critical_software_updates: + body: Nove versiones critic de Mastodon ha essite publicate, tu poterea voler actualisar al plus tosto possibile! subject: Actualisationes critic de Mastodon es disponibile pro %{instance}! + new_pending_account: + body: Le detalios del nove conto es infra. + subject: Nove conto preste a revider sur %{instance} (%{username}) + new_report: + body: "%{reporter} ha reportate %{target}" + body_remote: Alcuno de %{domain} ha reportate %{target} + subject: Nove reporto pro %{instance} (#%{id}) new_software_updates: subject: Nove versiones de Mastodon es disponibile pro %{instance}! new_trends: + body: 'Le sequente elementos besoniar de un recension ante que illos pote esser monstrate publicamente:' new_trending_links: title: Ligamines de tendentia new_trending_statuses: title: Messages de tendentia new_trending_tags: title: Hashtags de tendentia + subject: Nove tendentias pro recenser sur %{instance} aliases: add_new: Crear alias + created_msg: Create con successo un nove alias. Ora tu pote initiar le motion ab le vetere conto. + deleted_msg: Removite con successo le alias. Mover de ille conto a isto non sera plus possibile. + empty: Tu non ha aliases. + hint_html: Si tu desira mover ab un altere conto a isto, ci tu pote crear un alias, que es requirite ante que tu pote continuar con mover sequaces ab le vetere conto a isto. Iste action per se mesme es innocue e reversibile. Le migration de conto es initiate ab le vetere conto. + remove: Disligar alias appearance: advanced_web_interface: Interfacie web avantiate + advanced_web_interface_hint: 'Si tu desira facer uso de tu integre largessa de schermo, le interfacie web avantiate te permitte de configurar plure columnas differente pro vider al mesme tempore tante informationes como tu vole: pagina principal, notificationes, chronogramma federate, ulle numero de listas e hashtags.' + animations_and_accessibility: Animationes e accessibilitate confirmation_dialogs: Dialogos de confirmation discovery: Discoperta localization: @@ -1013,6 +1044,7 @@ ia: auth: apply_for_account: Peter un conto captcha_confirmation: + help_html: Si tu ha problemas a solver le CAPTCHA, tu pote contactar nos per %{email} e nos pote assister te. hint_html: Justo un altere cosa! Nos debe confirmar que tu es un human (isto es assi proque nos pote mantener foras le spam!). Solve le CAPTCHA infra e clicca "Continuar". title: Controlo de securitate confirmations: @@ -1054,6 +1086,7 @@ ia: status: account_status: Stato del conto view_strikes: Examinar le admonitiones passate contra tu conto + use_security_key: Usar clave de securitate challenge: confirm: Continuar invalid_password: Contrasigno non valide @@ -1066,13 +1099,22 @@ ia: x_days: "%{count}d" x_minutes: "%{count} m" deletes: + challenge_not_passed: Le informationes que tu ha inserite non era correcte confirm_password: Insere tu contrasigno actual pro verificar tu identitate + confirm_username: Insere tu actual contrasigno pro verificar tu identitate proceed: Deler le conto success_msg: Tu conto esseva delite con successo warning: + before: 'Insere tu nomine de usator pro confirmar le procedura:' + caches: Contente que ha essite in cache per altere servitores pote persister data_removal: Tu messages e altere datos essera removite permanentemente email_change_html: Tu pote cambiar tu adresse de e-mail sin deler tu conto + email_contact_html: Si illo ancora non arriva, tu pote inviar email a %{email} pro peter adjuta + email_reconfirmation_html: Si tu non recipe le email de confirmation, tu pote politica de confidentialitate. username_available: Tu nomine de usator essera disponibile novemente + username_unavailable: Tu nomine de usator remanera indisponibile disputes: strikes: action_taken: Action prendite @@ -1103,24 +1145,41 @@ ia: your_appeal_approved: Tu appello ha essite approbate your_appeal_pending: Tu ha submittite un appello your_appeal_rejected: Tu appello ha essite rejectate + domain_validator: + invalid_domain: non es un nomine de dominio valide edit_profile: basic_information: Information basic other: Alteres errors: + '400': Le requesta que tu inviava era non valide o mal formate. + '403': Tu non ha le permisso pro acceder a iste pagina. + '404': Le pagina que tu cerca non es ci. + '406': Iste pagina non es disponibile in le formato requirite. + '410': Le pagina que tu cercava non plus existe ci. '422': content: Le verification de securitate ha fallite. Bloca tu le cookies? title: Falleva le verification de securitate + '429': Troppe requestas + '500': + content: Nos lo regretta, ma alco errate eveniva sur nostre extremo. + title: Iste pagina non es correcte + '503': Le pagina non poteva esser servite per un panna de servitor temporari. + noscript_html: A usar le application web Mastodon, activa JavaScript. In alternativa, tenta un del apps native de Mastodon pro tu platteforma. existing_username_validator: + not_found: impossibile trovar un usator local con ille nomine de usator not_found_multiple: non poteva trovar %{usernames} exports: archive_takeout: date: Data download: Discargar tu archivo + hint_html: Tu pote requirer un archivo de tu messages e medios cargate. Le datos exportate sera in le formato ActivityPub, legibile per ulle software conforme. + in_progress: Compilante tu archivo... size: Dimension blocks: Tu ha blocate bookmarks: Marcapaginas csv: CSV domain_blocks: Blocadas de dominio + lists: Listas mutes: Tu ha silentiate storage: Immagazinage de medios featured_tags: @@ -1146,6 +1205,9 @@ ia: new: save: Salveguardar nove filtro title: Adder nove filtro + statuses: + index: + title: Messages filtrate generic: all: Toto cancel: Cancellar @@ -1153,6 +1215,7 @@ ia: confirm: Confirmar copy: Copiar delete: Deler + none: Nemo order_by: Ordinar per save_changes: Salvar le cambios today: hodie @@ -1162,6 +1225,8 @@ ia: invalid_csv_file: 'File CSV non valide. Error: %{error}' too_large: Le file es troppo longe failures: Fallimentos + modes: + overwrite_long: Reimplaciar registros actual con le noves overwrite_preambles: blocking_html: Tu es sur le puncto de reimplaciar tu lista de blocadas per usque a %{total_items} contos proveniente de %{filename}. domain_blocking_html: Tu es sur le puncto de reimplaciar tu lista de blocadas de dominio per usque a %{total_items} dominios proveniente de %{filename}. @@ -1170,7 +1235,14 @@ ia: domain_blocking_html: Tu es sur le puncto de blocar usque a %{total_items} dominios a partir de %{filename}. preface: Tu pote importar datos que tu ha exportate de un altere servitor, como un lista de personas que tu seque o bloca. recent_imports: Importationes recente + states: + finished: Terminate + in_progress: In curso + scheduled: Planificate + unconfirmed: Non confirmate status: Stato + success: Tu datos era cargate con successo e sera processate in tempore debite + time_started: Initiate le titles: blocking: Importation de contos blocate bookmarks: Importation de marcapaginas @@ -1186,7 +1258,9 @@ ia: blocking: Lista de blocadas bookmarks: Marcapaginas domain_blocking: Lista de dominios blocate + following: Sequente lista lists: Listas + muting: Lista del silentiates upload: Incargar invites: delete: Disactivar @@ -1199,10 +1273,16 @@ ia: '604800': 1 septimana '86400': 1 die expires_in_prompt: Nunquam + generate: Generar ligamine de invitation + invalid: Iste invitation non es valide + max_uses: + one: un uso + other: "%{count} usos" title: Invitar personas login_activities: authentication_methods: password: contrasigno + webauthn: claves de securitate mail_subscriptions: unsubscribe: action: Si, desubscriber @@ -1220,10 +1300,16 @@ ia: title: Desubcriber migrations: errors: + move_to_self: non pote esser le conto actual not_found: non poterea esser trovate + moderation: + title: Moderation move_handler: carry_blocks_over_text: Iste usator ha cambiate de conto desde %{acct}, que tu habeva blocate. notification_mailer: + admin: + sign_up: + subject: "%{name} se ha inscribite" follow: title: Nove sequitor follow_request: @@ -1232,16 +1318,25 @@ ia: action: Responder poll: subject: Un inquesta de %{name} ha finite + otp_authentication: + enable: Activar pagination: next: Sequente preferences: other: Altere public_timelines: Chronologias public + privacy: + privacy: Confidentialitate + search: Cercar privacy_policy: title: Politica de confidentialitate relationships: activity: Activitate del conto + invited: Invitate most_recent: Plus recente + moved: Movite + mutual: Mutue + primary: Primari status: Stato del conto rss: content_warning: 'Advertimento de contento:' @@ -1273,6 +1368,7 @@ ia: current_session: Session actual date: Data description: "%{browser} sur %{platform}" + ip: IP platforms: adobe_air: Adobe Air android: Android @@ -1287,6 +1383,7 @@ ia: windows: Windows windows_mobile: Windows Mobile windows_phone: Windows Phone + title: Sessiones settings: account: Conto account_settings: Parametros de conto @@ -1316,6 +1413,7 @@ ia: vote: Votar show_more: Monstrar plus visibilities: + direct: Directe private_long: Solmente monstrar a sequitores public: Public statuses_cleanup: @@ -1342,6 +1440,7 @@ ia: add: Adder disable: Disactivar 2FA edit: Modificar + generate_recovery_codes: Generar codices de recuperation user_mailer: appeal_approved: action: Parametros de conto @@ -1350,8 +1449,11 @@ ia: explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite rejectate. warning: appeal: Submitter un appello + categories: + spam: Spam subject: disable: Tu conto %{acct} ha essite gelate + mark_statuses_as_sensitive: Tu messages sur %{acct} ha essite marcate como sensibile none: Advertimento pro %{acct} sensitive: Tu messages sur %{acct} essera marcate como sensibile a partir de ora silence: Tu conto %{acct} ha essite limitate @@ -1370,8 +1472,12 @@ ia: apps_step: Discarga nostre applicationes official. apps_title: Applicationes de Mastodon edit_profile_action: Personalisar + edit_profile_step: Impulsa tu interactiones con un profilo comprehensive. edit_profile_title: Personalisar tu profilo + explanation: Ecce alcun consilios pro initiar feature_action: Apprender plus + feature_audience_title: Crea tu auditorio in fiducia + feature_moderation_title: Moderation como deberea esser follow_action: Sequer post_title: Face tu prime message share_action: Compartir diff --git a/config/locales/ie.yml b/config/locales/ie.yml index 2b819c53de..473d7b750f 100644 --- a/config/locales/ie.yml +++ b/config/locales/ie.yml @@ -751,6 +751,7 @@ ie: desc_html: To ci usa extern scrites de hCaptcha, quel posse esser ínquietant pro rasones de securitá e privatie. In plu, it posse far li processu de registration mult plu desfacil (particularimen por tis con deshabilitás). Pro ti rasones, ples considerar alternativ mesuras, tales quam registration per aprobation o invitation. title: Exige que nov usatores solue un CAPTCHA por confirmar lor conto content_retention: + danger_zone: Zone de dangere preamble: Decider qualmen usator-generat contenete es inmagasinat in Mastodon. title: Retention de contenete default_noindex: @@ -1659,6 +1660,7 @@ ie: preferences: Preferenties profile: Public profil relationships: Sequetes e sequitores + severed_relationships: Detranchat relationes statuses_cleanup: Automatisat deletion de postas strikes: Admonimentes moderatori two_factor_authentication: 2-factor autentication @@ -1672,6 +1674,7 @@ ie: lost_followers: Perdit sequitores lost_follows: Perdit sequetes preamble: Tu posse perdir tis queles tu seque e tui sequitores quande tu blocca un domonia o quande tui moderatores decide suspender un lontan servitor. Tande, tu va posser descargar listes de dejuntet relationes, a inspecter e possibilmen importar sur un altri servitor. + purged: Information pri ti-ci servitor ha esset purgat per li administratores de tui servitor. type: Eveniment statuses: attached: diff --git a/config/locales/lt.yml b/config/locales/lt.yml index b815cada5c..552afa8301 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -507,6 +507,8 @@ lt: roles: everyone: Numatytieji leidimai everyone_full_description_html: Tai – bazinis vaidmuo, turintis įtakos visiems naudotojams, net ir tiems, kurie neturi priskirto vaidmens. Visi kiti vaidmenys iš jo paveldi teises. + privileges: + manage_taxonomies_description: Leidžia naudotojams peržiūrėti tendencingą turinį ir atnaujinti saitažodžių nustatymus settings: captcha_enabled: desc_html: Tai priklauso nuo hCaptcha išorinių skriptų, kurie gali kelti susirūpinimą dėl saugumo ir privatumo. Be to, dėl to registracijos procesas kai kuriems žmonėms (ypač neįgaliesiems) gali būti gerokai sunkiau prieinami. Dėl šių priežasčių apsvarstyk alternatyvias priemones, pavyzdžiui, patvirtinimu arba kvietimu grindžiamą registraciją. @@ -514,6 +516,7 @@ lt: danger_zone: Pavojinga zona discovery: public_timelines: Viešieji laiko skalės + trends: Tendencijos domain_blocks: all: Visiems registrations: @@ -526,6 +529,7 @@ lt: title: Medija no_status_selected: Jokie statusai nebuvo pakeisti, nes niekas nepasirinkta title: Paskyros statusai + trending: Tendencinga with_media: Su medija system_checks: elasticsearch_health_yellow: @@ -536,8 +540,45 @@ lt: message_html: Tavo Elasticsearch klasteris turi tik vieną mazgą, ES_PRESET turėtų būti nustatyta į single_node_cluster. title: Administracija trends: + allow: Leisti + approved: Patvirtinta + disallow: Neleisti + links: + allow: Leisti nuorodą + allow_provider: Leisti leidėją + description_html: Tai – nuorodos, kuriomis šiuo metu daug bendrinasi paskyros, iš kurių tavo serveris mato įrašus. Tai gali padėti naudotojams sužinoti, kas vyksta pasaulyje. Jokios nuorodos nerodomos viešai, kol nepatvirtinai leidėjo. Taip pat gali leisti arba atmesti atskiras nuorodas. + disallow: Neleisti nuorodą + disallow_provider: Neleisti leidėją + no_link_selected: Jokios nuorodos nebuvo pakeistos, nes nebuvo pasirinkta nė viena + publishers: + no_publisher_selected: Jokie leidėjai nebuvo pakeisti, nes nė vienas nebuvo pasirinktas + title: Tendencingos nuorodos + usage_comparison: Bendrinta %{today} kartų šiandien, palyginti su %{yesterday} vakar + not_allowed_to_trend: Neleidžiama tendencinguoti + only_allowed: Leidžiama tik + pending_review: Laukiama peržiūros preview_card_providers: + allowed: Nuorodos iš šio leidėjo gali tendencinguoti + description_html: Tai – domenai, iš kurių dažnai bendrinamos nuorodos tavo serveryje. Nuorodos netendencinguos, nebent nuorodos domenas yra patvirtintas. Tavo patvirtinimas (arba atmetimas) apima ir subdomenus. + rejected: Nuorodos iš šio leidėjo netendencinguos title: Leidėjai + rejected: Atmesta + statuses: + allow: Leisti įrašą + allow_account: Leisti autorių (-ę) + description_html: Tai – įrašai, apie kuriuos žino tavo serveris ir kuriais šiuo metu daug bendrinamasi ir kurie yra mėgstami. Tai gali padėti naujiems ir grįžtantiems naudotojams rasti daugiau žmonių, kuriuos galima sekti. Jokie įrašai nerodomi viešai, kol nepatvirtinai autoriaus (-ės), o autorius (-ė) leidžia savo paskyrą siūlyti kitiems. Taip pat gali leisti arba atmesti atskirus įrašus. + disallow: Neleisti įrašą + disallow_account: Neleisti autorių (-ę) + no_status_selected: Jokie tendencingi įrašai nebuvo pakeisti, nes nė vienas iš jų nebuvo pasirinktas + not_discoverable: Autorius (-ė) nesutiko, kad būtų galima juos atrasti + title: Tendencingi įrašai + tags: + not_trendable: Nepasirodys tendencijose + title: Tendencingos saitažodžiai + trendable: Gali pasirodyti tendencijose + trending_rank: 'Tendencinga #%{rank}' + title: Tendencijos + trending: Tendencinga warning_presets: add_new: Pridėti naują delete: Ištrinti @@ -554,6 +595,14 @@ lt: body: "%{reporter} parašė skundą apie %{target}" body_remote: Kažkas iš %{domain} parašė skundą apie %{target} subject: Naujas skundas %{instance} (#%{id}) + new_trends: + new_trending_links: + title: Tendencingos nuorodos + new_trending_statuses: + title: Tendencingi įrašai + new_trending_tags: + title: Tendencingos saitažodžiai + subject: Naujos tendencijos peržiūrimos %{instance} appearance: advanced_web_interface: Išplėstinė žiniatinklio sąsaja advanced_web_interface_hint: 'Jei nori išnaudoti visą ekrano plotį, išplėstinė žiniatinklio sąsaja leidžia sukonfigūruoti daug skirtingų stulpelių, kad vienu metu matytum tiek informacijos, kiek tik nori: Pagrindinis, pranešimai, federacinė laiko skalė, bet kokie sąrašai ir saitažodžiai.' @@ -925,8 +974,8 @@ lt: follows_subtitle: Sek gerai žinomas paskyras. follows_title: Ką sekti follows_view_more: Peržiūrėti daugiau sekamų žmonių - hashtags_subtitle: Naršyk, kas tendencinga per pastarąsias 2 dienas. - hashtags_title: Trendingiausi saitažodžiai + hashtags_subtitle: Naršyk, kas tendencinga per pastarąsias 2 dienas + hashtags_title: Tendencingos saitažodžiai hashtags_view_more: Peržiūrėti daugiau tendencingų saitažodžių post_action: Sukurti post_step: Sakyk labas pasauliui tekstu, nuotraukomis, vaizdo įrašais arba apklausomis. diff --git a/config/locales/simple_form.cs.yml b/config/locales/simple_form.cs.yml index 54edc4149d..0b1a34e1b9 100644 --- a/config/locales/simple_form.cs.yml +++ b/config/locales/simple_form.cs.yml @@ -77,11 +77,13 @@ cs: warn: Schovat filtrovaný obsah za varováním zmiňujicím název filtru form_admin_settings: activity_api_enabled: Počty lokálně zveřejnělých příspěvků, aktivních uživatelů a nových registrací v týdenních intervalech + app_icon: WEBP, PNG, GIF nebo JPG. Nahradí výchozí ikonu aplikace v mobilních zařízeních vlastní ikonou. backups_retention_period: Uživatelé mají možnost vytvářet archivy svých příspěvků, které si mohou stáhnout později. Pokud je nastaveno na kladnou hodnotu, budou tyto archivy po zadaném počtu dní automaticky odstraněny z úložiště. bootstrap_timeline_accounts: Tyto účty budou připnuty na vrchol nových uživatelů podle doporučení. closed_registrations_message: Zobrazeno při zavření registrace content_cache_retention_period: Všechny příspěvky z jiných serverů (včetně boostů a odpovědí) budou po uplynutí stanoveného počtu dní smazány bez ohledu na interakci místního uživatele s těmito příspěvky. To se týká i příspěvků, které místní uživatel přidal do záložek nebo oblíbených. Soukromé zmínky mezi uživateli z různých instancí budou rovněž ztraceny a nebude možné je obnovit. Použití tohoto nastavení je určeno pro instance pro speciální účely a při implementaci pro obecné použití porušuje mnohá očekávání uživatelů. custom_css: Můžete použít vlastní styly ve verzi Mastodonu. + favicon: WEBP, PNG, GIF nebo JPG. Nahradí výchozí favicon Mastodonu vlastní ikonou. mascot: Přepíše ilustraci v pokročilém webovém rozhraní. media_cache_retention_period: Mediální soubory z příspěvků vzdálených uživatelů se ukládají do mezipaměti na vašem serveru. Pokud je nastaveno na kladnou hodnotu, budou média po zadaném počtu dní odstraněna. Pokud jsou mediální data vyžádána po jejich odstranění, budou znovu stažena, pokud je zdrojový obsah stále k dispozici. Vzhledem k omezením týkajícím se četnosti dotazů karet náhledů odkazů na weby třetích stran se doporučuje nastavit tuto hodnotu alespoň na 14 dní, jinak nebudou karty náhledů odkazů na vyžádání aktualizovány dříve. peers_api_enabled: Seznam názvů domén se kterými se tento server setkal ve fediversu. Neobsahuje žádná data o tom, zda jste federovali s daným serverem, pouze že o něm váš server ví. Toto je využíváno službami, které sbírají o federování statistiku v obecném smyslu. diff --git a/config/locales/simple_form.es-MX.yml b/config/locales/simple_form.es-MX.yml index 90e223dec3..b3c8a857e8 100644 --- a/config/locales/simple_form.es-MX.yml +++ b/config/locales/simple_form.es-MX.yml @@ -77,11 +77,13 @@ es-MX: warn: Ocultar el contenido filtrado detrás de una advertencia mencionando el título del filtro form_admin_settings: activity_api_enabled: Conteo de publicaciones publicadas localmente, usuarios activos, y nuevos registros en periodos semanales + app_icon: WEBP, PNG, GIF o JPG. Reemplaza el icono de aplicación predeterminado en dispositivos móviles con un icono personalizado. backups_retention_period: Los usuarios tienen la capacidad de generar archivos de sus mensajes para descargar más adelante. Cuando se establece un valor positivo, estos archivos se eliminarán automáticamente del almacenamiento después del número de días especificado. bootstrap_timeline_accounts: Estas cuentas aparecerán en la parte superior de las recomendaciones de los nuevos usuarios. closed_registrations_message: Mostrado cuando los registros están cerrados content_cache_retention_period: Todas las publicaciones de otros servidores (incluso impulsos y respuestas) se eliminarán después del número de días especificado, sin tener en cuenta la interacción del usuario local con esos mensajes. Esto incluye mensajes donde un usuario local los ha marcado como marcadores o favoritos. Las menciones privadas entre usuarios de diferentes instancias también se perderán sin posibilidad de recuperación. El uso de esta configuración está destinado a instancias de propósito especial, y rompe muchas expectativas de los usuarios cuando se implementa para un uso de propósito general. custom_css: Puedes aplicar estilos personalizados a la versión web de Mastodon. + favicon: WEBP, PNG, GIF o JPG. Reemplaza el favicon predeterminado de Mastodon con un icono personalizado. mascot: Reemplaza la ilustración en la interfaz web avanzada. media_cache_retention_period: Los archivos multimedia de las publicaciones creadas por usuarios remotos se almacenan en caché en tu servidor. Cuando se establece un valor positivo, estos archivos se eliminarán después del número especificado de días. Si los datos multimedia se solicitan después de eliminarse, se volverán a descargar, si el contenido fuente todavía está disponible. Debido a restricciones en la frecuencia con la que las tarjetas de previsualización de enlaces realizan peticiones a sitios de terceros, se recomienda establecer este valor a al menos 14 días, o las tarjetas de previsualización de enlaces no se actualizarán bajo demanda antes de ese momento. peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el fediverso. Aquí no se incluye ningún dato sobre si usted federa con un servidor determinado, sólo que su servidor lo sabe. Esto es utilizado por los servicios que recopilan estadísticas sobre la federación en un sentido general. diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml index 1d75bc4234..2fb5cab987 100644 --- a/config/locales/simple_form.es.yml +++ b/config/locales/simple_form.es.yml @@ -77,11 +77,13 @@ es: warn: Ocultar el contenido filtrado detrás de una advertencia mencionando el título del filtro form_admin_settings: activity_api_enabled: Conteo de publicaciones publicadas localmente, usuarios activos y registros nuevos cada semana + app_icon: WEBP, PNG, GIF o JPG. Reemplaza el icono de aplicación predeterminado en dispositivos móviles con un icono personalizado. backups_retention_period: Los usuarios tienen la capacidad de generar archivos de sus mensajes para descargar más adelante. Cuando se establece un valor positivo, estos archivos se eliminarán automáticamente del almacenamiento después del número de días especificado. bootstrap_timeline_accounts: Estas cuentas aparecerán en la parte superior de las recomendaciones de los nuevos usuarios. closed_registrations_message: Mostrado cuando los registros están cerrados content_cache_retention_period: Todas las publicaciones de otros servidores (incluso impulsos y respuestas) se eliminarán después del número de días especificado, sin tener en cuenta la interacción del usuario local con esos mensajes. Esto incluye mensajes donde un usuario local los ha marcado como marcadores o favoritos. Las menciones privadas entre usuarios de diferentes instancias también se perderán sin posibilidad de recuperación. El uso de esta configuración está destinado a instancias de propósito especial, y rompe muchas expectativas de los usuarios cuando se implementa para un uso de propósito general. custom_css: Puedes aplicar estilos personalizados a la versión web de Mastodon. + favicon: WEBP, PNG, GIF o JPG. Reemplaza el favicon predeterminado de Mastodon con un icono personalizado. mascot: Reemplaza la ilustración en la interfaz web avanzada. media_cache_retention_period: Los archivos multimedia de las publicaciones creadas por usuarios remotos se almacenan en caché en tu servidor. Cuando se establece un valor positivo, estos archivos se eliminarán después del número especificado de días. Si los datos multimedia se solicitan después de eliminarse, se volverán a descargar, si el contenido fuente todavía está disponible. Debido a restricciones en la frecuencia con la que las tarjetas de previsualización de enlaces realizan peticiones a sitios de terceros, se recomienda establecer este valor a al menos 14 días, o las tarjetas de previsualización de enlaces no se actualizarán bajo demanda antes de ese momento. peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el Fediverso. Aquí no se incluye ningún dato sobre si federas con un servidor determinado, solo que tu servidor lo conoce. Esto es utilizado por los servicios que recopilan estadísticas sobre la federación en un sentido general. diff --git a/config/locales/simple_form.ie.yml b/config/locales/simple_form.ie.yml index e482bd828c..2b995e7efa 100644 --- a/config/locales/simple_form.ie.yml +++ b/config/locales/simple_form.ie.yml @@ -77,10 +77,15 @@ ie: warn: Celar li contenete filtrat detra un avise mentionant li titul del filtre form_admin_settings: activity_api_enabled: Númeres de postas publicat localmen, activ usatores, e nov adhesiones in periodes semanal + app_icon: WEBP, PNG, GIF o JPG. Remplazza li predenifit favicon Mastodon sur mobiles con un icon customisat. + backups_retention_period: Usatores posse generar archives de lor postas por adcargar plu tard. Si on specifica un valore positiv, li archives va esser automaticmen deletet de tui magazinage pos li specificat quantitá de dies. bootstrap_timeline_accounts: Ti-ci contos va esser pinglat al parte superiori del recomandationes por nov usatores. closed_registrations_message: Monstrat quande adhesiones es cludet + content_cache_retention_period: Omni postas de altri servitores (includente boosts e responses) va esser deletet pos li specificat quantitá de dies, sin egard a local usator-interactiones con les. To vale anc por postas queles un local usator ha marcat o favoritat it. Anc privat mentiones ínter usatores de diferent instanties va esser perdit e ínrestorabil. Talmen, ti-ci parametre es intentet por scopes special pro que it posse ruptes li expectationes de usatores. custom_css: On posse aplicar customisat stiles al web-version de Mastodon. + favicon: WEBP, PNG, GIF oo JPG. Remplazza li predenifit favicon Mastodon con in icon customisat. mascot: Substitue li ilustration in li avansat interfacie web. + media_cache_retention_period: Files de medie de postas creat de lontan usatores es cachat sur tui servitor. Si on specifica un valore positiv, ili va esser automaticmen deletet pos li specificat quantitá de dies. Si on peti li data del medie pos deletion, it va esser re-descargat si li original fonte es disponibil. Restrictiones pri li frequentie de ligament-previsiones posse exister sur altri situs, e pro to it es recomandat que on usa un valore de adminim 14 dies; altrimen, li ligament-previsiones ne va esser actualisat secun demande ante ti témpor. peers_api_enabled: Un liste de nómines de dominia queles ti-ci servitor ha incontrat in li fediverse. Ci null data es includet pri ca tu confedera con un cert servitor o ne; it indica solmen que tui servitor conosse it. Usat per servicies colectent general statisticas pri federation. profile_directory: Li profilarium monstra omni usatores volent esser decovribil. require_invite_text: Quande registrationes besona manual aprobation, fa que li textu "Pro quo tu vole registrar te?" es obligatori vice facultativ @@ -240,6 +245,7 @@ ie: backups_retention_period: Periode de retener archives de usator bootstrap_timeline_accounts: Sempre recomandar ti-ci contos a nov usatores closed_registrations_message: Customisat missage quande registration ne disponibil + content_cache_retention_period: Periode de retention por contenete lontan custom_css: Custom CSS mascot: Customisat mascot (hereditat) media_cache_retention_period: Periode de retention por cachat medie diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index caf4c54299..c0698c3f7a 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -77,11 +77,13 @@ ja: warn: フィルタに一致した投稿を非表示にし、フィルタのタイトルを含む警告を表示します form_admin_settings: activity_api_enabled: 週単位でローカルで公開された投稿数、アクティブユーザー数、新規登録者数を表示します + app_icon: モバイル端末で表示されるデフォルトのアプリアイコンを独自のアイコンで上書きします。WEBP、PNG、GIF、JPGが利用可能です。 backups_retention_period: ユーザーには、後でダウンロードするために投稿のアーカイブを生成する機能があります。正の値に設定すると、これらのアーカイブは指定された日数後に自動的にストレージから削除されます。 bootstrap_timeline_accounts: これらのアカウントは、新しいユーザー向けのおすすめユーザーの一番上にピン留めされます。 closed_registrations_message: アカウント作成を停止している時に表示されます content_cache_retention_period: 他のサーバーからのすべての投稿(ブーストや返信を含む)は、指定された日数が経過すると、ローカルユーザーとのやりとりに関係なく削除されます。これには、ローカルユーザーがブックマークやお気に入りとして登録した投稿も含まれます。異なるサーバーのユーザー間の非公開な変身も失われ、復元することは不可能です。この設定の使用は特別な目的のインスタンスのためのものであり、一般的な目的のサーバーで使用するした場合、多くのユーザーの期待を裏切ることになります。 custom_css: ウェブ版のMastodonでカスタムスタイルを適用できます。 + favicon: デフォルトのMastodonのブックマークアイコンを独自のアイコンで上書きします。WEBP、PNG、GIF、JPGが利用可能です。 mascot: 上級者向けWebインターフェースのイラストを上書きします。 media_cache_retention_period: リモートユーザーが投稿したメディアファイルは、あなたのサーバーにキャッシュされます。正の値を設定すると、メディアは指定した日数後に削除されます。削除後にメディアデータが要求された場合、ソースコンテンツがまだ利用可能であれば、再ダウンロードされます。リンクプレビューカードがサードパーティのサイトを更新する頻度に制限があるため、この値を少なくとも14日に設定することをお勧めします。 peers_api_enabled: このサーバーが Fediverse で遭遇したドメイン名のリストです。このサーバーが知っているだけで、特定のサーバーと連合しているかのデータは含まれません。これは一般的に Fediverse に関する統計情報を収集するサービスによって使用されます。 diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index df4755c4fb..54d36eafe0 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -78,11 +78,14 @@ ko: form_admin_settings: activity_api_enabled: 주별 로컬에 게시된 글, 활성 사용자 및 새로운 가입자 수 app_icon: WEBP, PNG, GIF 또는 JPG. 모바일 기기에 쓰이는 기본 아이콘을 대체합니다. + backups_retention_period: 사용자들은 나중에 다운로드하기 위해 게시물 아카이브를 생성할 수 있습니다. 양수로 설정된 경우 이 아카이브들은 지정된 일수가 지난 후에 저장소에서 자동으로 삭제될 것입니다. bootstrap_timeline_accounts: 이 계정들은 팔로우 추천 목록 상단에 고정됩니다. closed_registrations_message: 새 가입을 차단했을 때 표시됩니다 + content_cache_retention_period: 다른 서버의 모든 게시물(부스트 및 답글 포함)은 해당 게시물에 대한 로컬 사용자의 상호 작용과 관계없이 지정된 일수가 지나면 삭제됩니다. 여기에는 로컬 사용자가 북마크 또는 즐겨찾기로 표시한 게시물도 포함됩니다. 다른 인스턴스 사용자와 주고 받은 비공개 멘션도 손실되며 복원할 수 없습니다. 이 설정은 특수 목적의 인스턴스를 위한 것이며 일반적인 용도의 많은 사용자의 예상이 빗나가게 됩니다. custom_css: 사용자 지정 스타일을 웹 버전의 마스토돈에 지정할 수 있습니다. favicon: WEBP, PNG, GIF 또는 JPG. 기본 파비콘을 대체합니다. mascot: 고급 웹 인터페이스의 그림을 대체합니다. + media_cache_retention_period: 원격 사용자가 작성한 글의 미디어 파일은 이 서버에 캐시됩니다. 양수로 설정하면 지정된 일수 후에 미디어가 삭제됩니다. 삭제된 후에 미디어 데이터를 요청하면 원본 콘텐츠를 사용할 수 있는 경우 다시 다운로드됩니다. 링크 미리 보기 카드가 타사 사이트를 폴링하는 빈도에 제한이 있으므로 이 값을 최소 14일로 설정하는 것이 좋으며, 그렇지 않으면 그 이전에는 링크 미리 보기 카드가 제때 업데이트되지 않을 것입니다. peers_api_enabled: 이 서버가 연합우주에서 만났던 서버들에 대한 도메인 네임의 목록입니다. 해당 서버와 어떤 연합을 했는지에 대한 정보는 전혀 포함되지 않고, 단순히 그 서버를 알고 있는지에 대한 것입니다. 이것은 일반적으로 연합에 대한 통계를 수집할 때 사용됩니다. profile_directory: 프로필 책자는 발견되기를 희망하는 모든 사람들의 목록을 나열합니다. require_invite_text: 가입이 수동 승인을 필요로 할 때, "왜 가입하려고 하나요?" 항목을 선택사항으로 두는 것보다는 필수로 두는 것이 낫습니다 diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index 6631b59b19..1c73ce0a84 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -85,6 +85,7 @@ lt: thumbnail: Maždaug 2:1 dydžio vaizdas, rodomas šalia tavo serverio informacijos. timeline_preview: Atsijungę lankytojai galės naršyti naujausius viešus įrašus, esančius serveryje. trends: Trendai rodo, kurios įrašai, saitažodžiai ir naujienų istorijos tavo serveryje sulaukia didžiausio susidomėjimo. + trends_as_landing_page: Rodyti tendencingą turinį atsijungusiems naudotojams ir lankytojams vietoj šio serverio aprašymo. Reikia, kad tendencijos būtų įjungtos. rule: hint: Pasirinktinai. Pateik daugiau informacijos apie taisyklę. sessions: @@ -169,6 +170,9 @@ lt: site_title: Serverio pavadinimas theme: Numatytoji tema thumbnail: Serverio miniatūra + trendable_by_default: Leisti tendencijas be išankstinės peržiūros + trends: Įjungti tendencijas + trends_as_landing_page: Naudoti tendencijas kaip nukreipimo puslapį invite_request: text: Kodėl nori prisijungti? notification_emails: @@ -181,6 +185,7 @@ lt: software_updates: label: Yra nauja Mastodon versija patch: Pranešti apie klaidų ištaisymo atnaujinimus + trending_tag: Reikia peržiūros naujam tendencijai rule: hint: Papildoma informacija text: Taisyklė diff --git a/config/locales/th.yml b/config/locales/th.yml index 8a001d8755..56b7bea69a 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -1838,6 +1838,9 @@ th: feature_action: เรียนรู้เพิ่มเติม feature_audience: Mastodon มีความพิเศษที่ให้คุณจัดการผู้รับสารของคุณได้โดยไม่มีตัวกลาง นอกจากนี้ การติดตั้ง Mastodon บนโครงสร้างพื้นฐานของคุณจะทำให้คุณสามารถติดตาม (และติดตามโดย) เซิร์ฟเวอร์ Mastodon แห่งไหนก็ได้ที่ทำงานอยู่ โดยไม่มีใครสามารถควบคุมได้นอกจากคุณ feature_audience_title: สร้างผู้ชมของคุณด้วยความมั่นใจ + feature_control_title: การควบคุมเส้นเวลาของคุณเอง + feature_creativity_title: ความคิดสร้างสรรค์ที่ไม่มีใครเทียบได้ + feature_moderation_title: การกลั่นกรองในแบบที่ควรจะเป็น follow_action: ติดตาม follow_step: การติดตามผู้คนที่น่าสนใจคือสิ่งที่ Mastodon ให้ความสำคัญ follow_title: ปรับแต่งฟีดหน้าแรกของคุณ From b5b84fad65f927a1bf55538be4a4763199724a6e Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 14 May 2024 19:54:28 +0200 Subject: [PATCH 151/658] Fix OpenSearch compatibility issue (#30278) --- .github/workflows/test-ruby.yml | 20 ++++++++++++++++++-- config/application.rb | 1 + lib/elasticsearch/client_extensions.rb | 11 +++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 lib/elasticsearch/client_extensions.rb diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 45dc8a0deb..2bfa59e6b1 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -264,8 +264,8 @@ jobs: ports: - 6379:6379 - search: - image: ${{ matrix.search-image }} + elasticsearch: + image: ${{ contains(matrix.search-image, 'elasticsearch') && matrix.search-image || '' }} env: discovery.type: single-node xpack.security.enabled: false @@ -277,6 +277,20 @@ jobs: ports: - 9200:9200 + opensearch: + image: ${{ contains(matrix.search-image, 'opensearch') && matrix.search-image || '' }} + env: + discovery.type: single-node + DISABLE_INSTALL_DEMO_CONFIG: true + DISABLE_SECURITY_PLUGIN: true + options: >- + --health-cmd "curl http://localhost:9200/_cluster/health" + --health-interval 10s + --health-timeout 5s + --health-retries 10 + ports: + - 9200:9200 + env: DB_HOST: localhost DB_USER: postgres @@ -300,6 +314,8 @@ jobs: include: - ruby-version: '.ruby-version' search-image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2 + - ruby-version: '.ruby-version' + search-image: opensearchproject/opensearch:2 steps: - uses: actions/checkout@v4 diff --git a/config/application.rb b/config/application.rb index 402c7f0614..07b50ca036 100644 --- a/config/application.rb +++ b/config/application.rb @@ -40,6 +40,7 @@ require_relative '../lib/mastodon/rack_middleware' require_relative '../lib/public_file_server_middleware' require_relative '../lib/devise/strategies/two_factor_ldap_authenticatable' require_relative '../lib/devise/strategies/two_factor_pam_authenticatable' +require_relative '../lib/elasticsearch/client_extensions' require_relative '../lib/chewy/settings_extensions' require_relative '../lib/chewy/index_extensions' require_relative '../lib/chewy/strategy/mastodon' diff --git a/lib/elasticsearch/client_extensions.rb b/lib/elasticsearch/client_extensions.rb new file mode 100644 index 0000000000..700bfa4a1c --- /dev/null +++ b/lib/elasticsearch/client_extensions.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Elasticsearch + module ClientExtensions + def verify_elasticsearch + @verified = true + end + end +end + +Elasticsearch::Client.prepend(Elasticsearch::ClientExtensions) From 1bf661cddbc614d4076e9d9e855575fc29e976c0 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Tue, 14 May 2024 20:15:42 +0200 Subject: [PATCH 152/658] Fix missing prop warning for `` (#30291) --- app/javascript/mastodon/components/account.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx index 3282696d34..18a31cba24 100644 --- a/app/javascript/mastodon/components/account.jsx +++ b/app/javascript/mastodon/components/account.jsx @@ -172,7 +172,6 @@ Account.propTypes = { onBlock: PropTypes.func, onMute: PropTypes.func, onMuteNotifications: PropTypes.func, - intl: PropTypes.object.isRequired, hidden: PropTypes.bool, minimal: PropTypes.bool, defaultAction: PropTypes.string, From 160823716ab0fe57c629f470d7218218a78a37d4 Mon Sep 17 00:00:00 2001 From: David Lapshin Date: Mon, 13 May 2024 12:19:42 +0300 Subject: [PATCH 153/658] [Glitch] Add active animation to header settings button Port cb93c1edf08865b1ac528a9a4cb747dab3d57e8d to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/styles/components.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index f5518907ce..6e06898d84 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -4602,12 +4602,20 @@ a.status-card { outline: $ui-button-focus-outline; } + .no-reduce-motion .icon { + transition: transform 0.15s ease-in-out; + } + &.active { color: $primary-text-color; &:hover { color: $primary-text-color; } + + .icon { + transform: rotate(60deg); + } } &:disabled { From 47ce5f4ca9cec9f77e05c7b341275689674175ae Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Tue, 14 May 2024 20:15:42 +0200 Subject: [PATCH 154/658] [Glitch] Fix missing prop warning for `` Port 1bf661cddbc614d4076e9d9e855575fc29e976c0 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/components/account.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/javascript/flavours/glitch/components/account.jsx b/app/javascript/flavours/glitch/components/account.jsx index 326d4fcb69..038009cfa8 100644 --- a/app/javascript/flavours/glitch/components/account.jsx +++ b/app/javascript/flavours/glitch/components/account.jsx @@ -174,7 +174,6 @@ Account.propTypes = { onBlock: PropTypes.func, onMute: PropTypes.func, onMuteNotifications: PropTypes.func, - intl: PropTypes.object.isRequired, hidden: PropTypes.bool, minimal: PropTypes.bool, defaultAction: PropTypes.string, From 38a330f96328091fe39dd212ec053d5df3e2e36e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 10:25:34 +0200 Subject: [PATCH 155/658] fix(deps): update dependency core-js to v3.37.1 (#30293) 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 f6dc8f161a..90a7791e26 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6381,9 +6381,9 @@ __metadata: linkType: hard "core-js@npm:^3.30.2": - version: 3.37.0 - resolution: "core-js@npm:3.37.0" - checksum: 10c0/7e00331f346318ca3f595c08ce9e74ddae744715aef137486c1399163afd79792fb94c3161280863adfdc3e30f8026912d56bd3036f93cacfc689d33e185f2ee + version: 3.37.1 + resolution: "core-js@npm:3.37.1" + checksum: 10c0/440eb51a7a39128a320225fe349f870a3641b96c9ecd26470227db730ef8c161ea298eaea621db66ec0ff622a85299efb4e23afebf889c0a1748616102307675 languageName: node linkType: hard From 508e93eb649fb490ea98904e2f64b372ec2ff610 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 10:25:50 +0200 Subject: [PATCH 156/658] chore(deps): update dependency fog-openstack to v1.1.1 (#30295) 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 efc99eb23d..37910be8d3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -272,7 +272,7 @@ GEM fog-json (1.2.0) fog-core multi_json (~> 1.10) - fog-openstack (1.1.0) + fog-openstack (1.1.1) fog-core (~> 2.1) fog-json (>= 1.0) formatador (1.1.0) @@ -422,7 +422,7 @@ GEM memory_profiler (1.0.1) mime-types (3.5.2) mime-types-data (~> 3.2015) - mime-types-data (3.2024.0305) + mime-types-data (3.2024.0507) mini_mime (1.1.5) mini_portile2 (2.8.6) minitest (5.22.3) From 44e855db7830ab803820a9534f543702b9e9dca9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 08:26:22 +0000 Subject: [PATCH 157/658] chore(deps): update dependency nokogiri to v1.16.5 [security] (#30289) 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 37910be8d3..95ab6f08f5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -445,7 +445,7 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.1) - nokogiri (1.16.4) + nokogiri (1.16.5) mini_portile2 (~> 2.8.2) racc (~> 1.4) nsa (0.3.0) From 40639510f88442f9e21f9400931038cce7a0518c Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Wed, 15 May 2024 10:27:34 +0200 Subject: [PATCH 158/658] Retain unconfirmed users longer (1 week) (#30285) --- app/workers/scheduler/user_cleanup_scheduler.rb | 7 +++++-- spec/workers/scheduler/user_cleanup_scheduler_spec.rb | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/workers/scheduler/user_cleanup_scheduler.rb b/app/workers/scheduler/user_cleanup_scheduler.rb index 2d2efc731a..63ea876e50 100644 --- a/app/workers/scheduler/user_cleanup_scheduler.rb +++ b/app/workers/scheduler/user_cleanup_scheduler.rb @@ -3,6 +3,9 @@ class Scheduler::UserCleanupScheduler include Sidekiq::Worker + UNCONFIRMED_ACCOUNTS_MAX_AGE_DAYS = 7 + DISCARDED_STATUSES_MAX_AGE_DAYS = 30 + sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 1.day.to_i def perform @@ -13,7 +16,7 @@ class Scheduler::UserCleanupScheduler private def clean_unconfirmed_accounts! - User.where('confirmed_at is NULL AND confirmation_sent_at <= ?', 2.days.ago).reorder(nil).find_in_batches do |batch| + User.where('confirmed_at is NULL AND confirmation_sent_at <= ?', UNCONFIRMED_ACCOUNTS_MAX_AGE_DAYS.days.ago).reorder(nil).find_in_batches do |batch| # We have to do it separately because of missing database constraints AccountModerationNote.where(target_account_id: batch.map(&:account_id)).delete_all Account.where(id: batch.map(&:account_id)).delete_all @@ -22,7 +25,7 @@ class Scheduler::UserCleanupScheduler end def clean_discarded_statuses! - Status.unscoped.discarded.where('deleted_at <= ?', 30.days.ago).find_in_batches do |statuses| + Status.unscoped.discarded.where('deleted_at <= ?', DISCARDED_STATUSES_MAX_AGE_DAYS.days.ago).find_in_batches do |statuses| RemovalWorker.push_bulk(statuses) do |status| [status.id, { 'immediate' => true, 'skip_streaming' => true }] end diff --git a/spec/workers/scheduler/user_cleanup_scheduler_spec.rb b/spec/workers/scheduler/user_cleanup_scheduler_spec.rb index 8fda246ba8..c3940901d4 100644 --- a/spec/workers/scheduler/user_cleanup_scheduler_spec.rb +++ b/spec/workers/scheduler/user_cleanup_scheduler_spec.rb @@ -14,7 +14,7 @@ describe Scheduler::UserCleanupScheduler do before do # Need to update the already-existing users because their initialization overrides confirmation_sent_at new_unconfirmed_user.update!(confirmed_at: nil, confirmation_sent_at: Time.now.utc) - old_unconfirmed_user.update!(confirmed_at: nil, confirmation_sent_at: 1.week.ago) + old_unconfirmed_user.update!(confirmed_at: nil, confirmation_sent_at: 10.days.ago) confirmed_user.update!(confirmed_at: 1.day.ago) end From 7f7eba875376a44e01d4446902888e6afdd88908 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 10:34:50 +0200 Subject: [PATCH 159/658] chore(deps): update dependency letter_opener_web to v3 (#30296) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 247865aacf..b9baef7036 100644 --- a/Gemfile +++ b/Gemfile @@ -178,7 +178,7 @@ group :development do # Preview mail in the browser gem 'letter_opener', '~> 1.8' - gem 'letter_opener_web', '~> 2.0' + gem 'letter_opener_web', '~> 3.0' # Security analysis CLI tools gem 'brakeman', '~> 6.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 95ab6f08f5..2854528b73 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -389,10 +389,10 @@ GEM addressable (~> 2.8) letter_opener (1.10.0) launchy (>= 2.2, < 4) - letter_opener_web (2.0.0) - actionmailer (>= 5.2) - letter_opener (~> 1.7) - railties (>= 5.2) + letter_opener_web (3.0.0) + actionmailer (>= 6.1) + letter_opener (~> 1.9) + railties (>= 6.1) rexml link_header (0.0.8) llhttp-ffi (0.5.0) @@ -434,7 +434,7 @@ GEM uri net-http-persistent (4.0.2) connection_pool (~> 2.2) - net-imap (0.4.10) + net-imap (0.4.11) date net-protocol net-ldap (0.19.0) @@ -686,7 +686,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.9.0) - reline (0.5.6) + reline (0.5.7) io-console (~> 0.5) request_store (1.6.0) rack (>= 1.4) @@ -893,7 +893,7 @@ GEM xorcist (1.1.3) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.13) + zeitwerk (2.6.14) PLATFORMS ruby @@ -955,7 +955,7 @@ DEPENDENCIES kaminari (~> 1.2) kt-paperclip (~> 7.2) letter_opener (~> 1.8) - letter_opener_web (~> 2.0) + letter_opener_web (~> 3.0) link_header (~> 0.0) lograge (~> 0.12) mail (~> 2.8) From 78a8263f73ed8b07a1528e716f28858e0d817603 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 10:34:58 +0200 Subject: [PATCH 160/658] fix(deps): update dependency postcss-preset-env to v9.5.13 (#30286) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 62 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/yarn.lock b/yarn.lock index 90a7791e26..3741a54195 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1617,15 +1617,15 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-cascade-layers@npm:^4.0.5": - version: 4.0.5 - resolution: "@csstools/postcss-cascade-layers@npm:4.0.5" +"@csstools/postcss-cascade-layers@npm:^4.0.6": + version: 4.0.6 + resolution: "@csstools/postcss-cascade-layers@npm:4.0.6" dependencies: - "@csstools/selector-specificity": "npm:^3.1.0" + "@csstools/selector-specificity": "npm:^3.1.1" postcss-selector-parser: "npm:^6.0.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/2b6dd33b51df349dd89b12ebe3240d65accb0ba03e40288a72e26cf2307a7bdd742c42d9ff7a3f886cab19b2f8813978075f6ee61a985b0b7ceac7e2cbb29e04 + checksum: 10c0/134019e9b3f71de39034658e2a284f549883745a309f774d8d272871f9e65680e0981c893766537a8a56ed7f41dba2d0f9fc3cb4fa4057c227bc193976a2ec79 languageName: node linkType: hard @@ -1749,15 +1749,15 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-is-pseudo-class@npm:^4.0.7": - version: 4.0.7 - resolution: "@csstools/postcss-is-pseudo-class@npm:4.0.7" +"@csstools/postcss-is-pseudo-class@npm:^4.0.8": + version: 4.0.8 + resolution: "@csstools/postcss-is-pseudo-class@npm:4.0.8" dependencies: - "@csstools/selector-specificity": "npm:^3.1.0" + "@csstools/selector-specificity": "npm:^3.1.1" postcss-selector-parser: "npm:^6.0.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/43668987df4608f822dbc323d3ac567fa7c192235b55933fd5d1855977ead80184512eb64a3f45a020fdd93711952ba8e9f9a280f4e981625b68a9ff074f9a01 + checksum: 10c0/82f191571c3e0973354a54ef15feeb17f9408b4abbefad19fc0f087683b1212fc854cdf09a47324267dd47be4c5cb47d63b8d083695a67c3f8f3e53df3d561f6 languageName: node linkType: hard @@ -1983,12 +1983,12 @@ __metadata: languageName: node linkType: hard -"@csstools/selector-specificity@npm:^3.0.3, @csstools/selector-specificity@npm:^3.1.0": - version: 3.1.0 - resolution: "@csstools/selector-specificity@npm:3.1.0" +"@csstools/selector-specificity@npm:^3.0.3, @csstools/selector-specificity@npm:^3.1.1": + version: 3.1.1 + resolution: "@csstools/selector-specificity@npm:3.1.1" peerDependencies: postcss-selector-parser: ^6.0.13 - checksum: 10c0/7f77f8377b637dcca7f7a9d6ace3329cf60f02cbd75f14241de30b1f5d00c961ec167572bc93517cdb2f106405a91119f026389a0f96dabae8dd67d1c7710e60 + checksum: 10c0/1d4a3f8015904d6aeb3203afe0e1f6db09b191d9c1557520e3e960c9204ad852df9db4cbde848643f78a26f6ea09101b4e528dbb9193052db28258dbcc8a6e1d languageName: node linkType: hard @@ -6577,16 +6577,16 @@ __metadata: languageName: node linkType: hard -"css-has-pseudo@npm:^6.0.4": - version: 6.0.4 - resolution: "css-has-pseudo@npm:6.0.4" +"css-has-pseudo@npm:^6.0.5": + version: 6.0.5 + resolution: "css-has-pseudo@npm:6.0.5" dependencies: - "@csstools/selector-specificity": "npm:^3.1.0" + "@csstools/selector-specificity": "npm:^3.1.1" postcss-selector-parser: "npm:^6.0.13" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/e9d440de483e15092ebaadb483502243f43e0457d4214c8012ebdba7a959e74d40714254bf97247780e65735512f248a55feda0b3975d9a5eaea9c746f7518f0 + checksum: 10c0/946930b7e699d6dbcb8426ebcd593228ee0e2143a148fb2399111ea4c9ed8d6eb3447e944251f1be44ae987d5ab16e450b0b006ca197f318c2a3760ba431fbb9 languageName: node linkType: hard @@ -13548,16 +13548,16 @@ __metadata: languageName: node linkType: hard -"postcss-nesting@npm:^12.1.3": - version: 12.1.3 - resolution: "postcss-nesting@npm:12.1.3" +"postcss-nesting@npm:^12.1.4": + version: 12.1.4 + resolution: "postcss-nesting@npm:12.1.4" dependencies: "@csstools/selector-resolve-nested": "npm:^1.1.0" - "@csstools/selector-specificity": "npm:^3.1.0" + "@csstools/selector-specificity": "npm:^3.1.1" postcss-selector-parser: "npm:^6.0.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/6b2d3a4823e85592965c6c11f749c5357703256e7334388147d6a3bb72a3abbe47789afaa8535bdd7a9bd6d0099eb12ffec6c154050d8e8b8286b1adbed5b397 + checksum: 10c0/b3408de4c04b58a88a56fa81aeff59b12615c78d4f5a57e09c1ee47e74cff51f8c9cad1684da0059067303cf65b4b688f85f0c5ca8d54af8c4ab998f727ab9fd languageName: node linkType: hard @@ -13712,10 +13712,10 @@ __metadata: linkType: hard "postcss-preset-env@npm:^9.5.2": - version: 9.5.12 - resolution: "postcss-preset-env@npm:9.5.12" + version: 9.5.13 + resolution: "postcss-preset-env@npm:9.5.13" dependencies: - "@csstools/postcss-cascade-layers": "npm:^4.0.5" + "@csstools/postcss-cascade-layers": "npm:^4.0.6" "@csstools/postcss-color-function": "npm:^3.0.16" "@csstools/postcss-color-mix-function": "npm:^2.0.16" "@csstools/postcss-exponential-functions": "npm:^1.0.7" @@ -13725,7 +13725,7 @@ __metadata: "@csstools/postcss-hwb-function": "npm:^3.0.15" "@csstools/postcss-ic-unit": "npm:^3.0.6" "@csstools/postcss-initial": "npm:^1.0.1" - "@csstools/postcss-is-pseudo-class": "npm:^4.0.7" + "@csstools/postcss-is-pseudo-class": "npm:^4.0.8" "@csstools/postcss-light-dark-function": "npm:^1.0.5" "@csstools/postcss-logical-float-and-clear": "npm:^2.0.1" "@csstools/postcss-logical-overflow": "npm:^1.0.1" @@ -13747,7 +13747,7 @@ __metadata: autoprefixer: "npm:^10.4.19" browserslist: "npm:^4.22.3" css-blank-pseudo: "npm:^6.0.2" - css-has-pseudo: "npm:^6.0.4" + css-has-pseudo: "npm:^6.0.5" css-prefers-color-scheme: "npm:^9.0.1" cssdb: "npm:^8.0.0" postcss-attribute-case-insensitive: "npm:^6.0.3" @@ -13767,7 +13767,7 @@ __metadata: postcss-image-set-function: "npm:^6.0.3" postcss-lab-function: "npm:^6.0.16" postcss-logical: "npm:^7.0.1" - postcss-nesting: "npm:^12.1.3" + postcss-nesting: "npm:^12.1.4" postcss-opacity-percentage: "npm:^2.0.0" postcss-overflow-shorthand: "npm:^5.0.1" postcss-page-break: "npm:^3.0.4" @@ -13777,7 +13777,7 @@ __metadata: postcss-selector-not: "npm:^7.0.2" peerDependencies: postcss: ^8.4 - checksum: 10c0/3e0276b2061baa396547f9c0090fcb0c6149d3735c7aefa99a8e520701aae0b7265578b59d5e4efa9f5e61659c161e39590a5d63bac49469b99da1c549b63231 + checksum: 10c0/5bbb6e87b1b3acc816ef445836f85df5f50ac96bdc3d571952a83794c80863c652d27ab14c66f6b88f86f5664119d49b357e4184162022cc3436676f3fbe833b languageName: node linkType: hard From aad5e841b59691f001132a9cf96487db8389c77e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 10:53:57 +0200 Subject: [PATCH 161/658] New Crowdin Translations (automated) (#30290) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/cy.json | 1 + app/javascript/mastodon/locales/en-GB.json | 13 ++ app/javascript/mastodon/locales/gl.json | 1 + app/javascript/mastodon/locales/sk.json | 4 + config/locales/devise.ia.yml | 4 + config/locales/doorkeeper.en-GB.yml | 1 + config/locales/doorkeeper.ia.yml | 21 +++ config/locales/en-GB.yml | 1 + config/locales/ia.yml | 141 +++++++++++++++++++++ config/locales/simple_form.cy.yml | 2 + config/locales/simple_form.en-GB.yml | 6 + 11 files changed, 195 insertions(+) diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 925b7710e0..2c59769959 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -474,6 +474,7 @@ "notification.follow_request": "Mae {name} wedi gwneud cais i'ch dilyn", "notification.mention": "Crybwyllodd {name} amdanoch chi", "notification.moderation-warning.learn_more": "Dysgu mwy", + "notification.moderation_warning": "Rydych wedi derbyn rhybudd gan gymedrolwr", "notification.moderation_warning.action_delete_statuses": "Mae rhai o'ch postiadau wedi'u dileu.", "notification.moderation_warning.action_disable": "Mae eich cyfrif wedi'i analluogi.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Mae rhai o'ch postiadau wedi'u marcio'n sensitif.", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 6c24d5a261..e70348e0b2 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.", "follow_suggestions.curated_suggestion": "Staff pick", "follow_suggestions.dismiss": "Don't show again", + "follow_suggestions.featured_longer": "Hand-picked by the {domain} team", + "follow_suggestions.friends_of_friends_longer": "Popular among people you follow", "follow_suggestions.hints.featured": "This profile has been hand-picked by the {domain} team.", "follow_suggestions.hints.friends_of_friends": "This profile is popular among the people you follow.", "follow_suggestions.hints.most_followed": "This profile is one of the most followed on {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "This profile is similar to the profiles you have most recently followed.", "follow_suggestions.personalized_suggestion": "Personalised suggestion", "follow_suggestions.popular_suggestion": "Popular suggestion", + "follow_suggestions.popular_suggestion_longer": "Popular on {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Similar to profiles you recently followed", "follow_suggestions.view_all": "View all", "follow_suggestions.who_to_follow": "Who to follow", "followed_tags": "Followed hashtags", @@ -469,6 +473,15 @@ "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", "notification.mention": "{name} mentioned you", + "notification.moderation-warning.learn_more": "Learn more", + "notification.moderation_warning": "You have received a moderation warning", + "notification.moderation_warning.action_delete_statuses": "Some of your posts have been removed.", + "notification.moderation_warning.action_disable": "Your account has been disabled.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Some of your posts have been marked as sensitive.", + "notification.moderation_warning.action_none": "Your account has received a moderation warning.", + "notification.moderation_warning.action_sensitive": "Your posts will be marked as sensitive from now on.", + "notification.moderation_warning.action_silence": "Your account has been limited.", + "notification.moderation_warning.action_suspend": "Your account has been suspended.", "notification.own_poll": "Your poll has ended", "notification.poll": "A poll you have voted in has ended", "notification.reblog": "{name} boosted your status", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index b2a50ebb81..88d4f5f60e 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -474,6 +474,7 @@ "notification.follow_request": "{name} solicitou seguirte", "notification.mention": "{name} mencionoute", "notification.moderation-warning.learn_more": "Saber máis", + "notification.moderation_warning": "Recibiches unha advertencia da moderación", "notification.moderation_warning.action_delete_statuses": "Algunha das túas publicacións foron eliminadas.", "notification.moderation_warning.action_disable": "A túa conta foi desactivada.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algunha das túas publicacións foron marcadas como sensibles.", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 2863442415..0c76467419 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -295,6 +295,7 @@ "follow_suggestions.personalized_suggestion": "Prispôsobený návrh", "follow_suggestions.popular_suggestion": "Obľúbený návrh", "follow_suggestions.popular_suggestion_longer": "Populárne na {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Podobné profilom ktoré si nedávno nasledoval/a", "follow_suggestions.view_all": "Zobraziť všetky", "follow_suggestions.who_to_follow": "Koho sledovať", "followed_tags": "Sledované hashtagy", @@ -445,10 +446,13 @@ "notification.follow_request": "{name} vás žiada sledovať", "notification.mention": "{name} vás spomína", "notification.moderation-warning.learn_more": "Zisti viac", + "notification.moderation_warning.action_silence": "Tvoj účet bol obmedzený.", + "notification.moderation_warning.action_suspend": "Tvoj účet bol pozastavený.", "notification.own_poll": "Vaša anketa sa skončila", "notification.poll": "Anketa, v ktorej ste hlasovali, sa skončila", "notification.reblog": "{name} zdieľa váš príspevok", "notification.relationships_severance_event": "Stratené prepojenia s {name}", + "notification.relationships_severance_event.account_suspension": "Správca z {from} pozastavil/a {target}, čo znamená, že od nich viac nemôžeš dostávať aktualizácie, alebo s nimi interaktovať.", "notification.relationships_severance_event.learn_more": "Zisti viac", "notification.status": "{name} uverejňuje niečo nové", "notification.update": "{name} upravuje príspevok", diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index d83c708647..c68efddd07 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -86,9 +86,13 @@ ia: 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. + sessions: + signed_in: Connexe con successo. + signed_out: Disconnexe con successo. unlocks: unlocked: Tu conto ha essite disblocate con successo. Initia session a continuar. errors: messages: already_confirmed: jam esseva confirmate, tenta initiar session not_found: non trovate + not_locked: non era blocate diff --git a/config/locales/doorkeeper.en-GB.yml b/config/locales/doorkeeper.en-GB.yml index b3ceffb13f..2e537c5301 100644 --- a/config/locales/doorkeeper.en-GB.yml +++ b/config/locales/doorkeeper.en-GB.yml @@ -174,6 +174,7 @@ en-GB: read:filters: see your filters read:follows: see your follows read:lists: see your lists + read:me: read only your account's basic information read:mutes: see your mutes read:notifications: see your notifications read:reports: see your reports diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index b5bd6cc536..dc96599681 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -4,6 +4,7 @@ ia: attributes: doorkeeper/application: name: Nomine de application + scopes: Ambitos website: Sito web de application errors: models: @@ -28,12 +29,14 @@ ia: empty: Tu non ha applicationes. name: Nomine new: Nove application + scopes: Ambitos show: Monstrar title: Tu applicationes new: title: Nove application show: actions: Actiones + application_id: Clave del cliente scopes: Ambitos title: 'Application: %{name}' authorizations: @@ -42,13 +45,20 @@ ia: deny: Negar error: title: Ocurreva un error + new: + review_permissions: Revisionar le permissos + title: Autorisation necessari authorized_applications: + buttons: + revoke: Revocar confirmations: revoke: Es tu secur? index: + authorized_at: Autorisate le %{date} last_used_at: Ultime uso in %{date} never_used: Nunquam usate scopes: Permissiones + superapp: Interne title: Tu applicationes autorisate flash: applications: @@ -58,12 +68,21 @@ ia: notice: Application delite. update: notice: Application actualisate. + authorized_applications: + destroy: + notice: Application revocate. grouped_scopes: + access: + read: Accesso de sol lectura + read/write: Accesso de lectura e scriptura + write: Accesso de sol scriptura title: accounts: Contos admin/accounts: Gestion de contos + admin/all: Tote le functiones administrative admin/reports: Gestion de reportos all: Accesso plen a tu conto de Mastodon + blocks: Blocadas bookmarks: Marcapaginas conversations: Conversationes favourites: Favoritos @@ -84,7 +103,9 @@ ia: oauth2_provider: Fornitor OAuth2 scopes: admin:read: leger tote le datos in le servitor + admin:read:accounts: leger information sensibile de tote le contos admin:write: modificar tote le datos in le servitor + follow: modificar relationes del contos read: leger tote le datos de tu conto read:accounts: vider informationes de conto read:bookmarks: vider tu marcapaginas diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index df956902a6..7e31080dfa 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -751,6 +751,7 @@ en-GB: desc_html: This relies on external scripts from hCaptcha, which may be a security and privacy concern. In addition, this can make the registration process significantly less accessible to some (especially disabled) people. For these reasons, please consider alternative measures such as approval-based or invite-based registration. title: Require new users to solve a CAPTCHA to confirm their account content_retention: + danger_zone: Danger zone preamble: Control how user-generated content is stored in Mastodon. title: Content retention default_noindex: diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 46cdcd3c68..68676a09f7 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -997,6 +997,7 @@ ia: body_remote: Alcuno de %{domain} ha reportate %{target} subject: Nove reporto pro %{instance} (#%{id}) new_software_updates: + body: Nove versiones de Mastodon ha essite publicate, tu poterea voler actualisar! subject: Nove versiones de Mastodon es disponibile pro %{instance}! new_trends: body: 'Le sequente elementos besoniar de un recension ante que illos pote esser monstrate publicamente:' @@ -1048,6 +1049,7 @@ ia: hint_html: Justo un altere cosa! Nos debe confirmar que tu es un human (isto es assi proque nos pote mantener foras le spam!). Solve le CAPTCHA infra e clicca "Continuar". title: Controlo de securitate confirmations: + awaiting_review: Tu adresse email es confirmate! Le personal de %{domain} ora revide tu registration. Tu recipera un email si illes approba tu conto! awaiting_review_title: Tu registration es revidite clicking_this_link: cliccante iste ligamine login_link: acceder @@ -1066,6 +1068,7 @@ ia: logout: Clauder le session migrate_account: Move a un conto differente or_log_in_with: O accede con + privacy_policy_agreement_html: Io ha legite e acceptar le politica de confidentialitate progress: confirm: Confirma le email details: Tu detalios @@ -1075,29 +1078,69 @@ ia: cas: CAS saml: SAML register: Inscribe te + registration_closed: "%{instance} non accepta nove membros" resend_confirmation: Reinviar ligamine de confirmation reset_password: Remontar le contrasigno rules: accept: Acceptar back: Retro + invited_by: 'Tu pote junger te a %{domain} gratias al invitation que tu ha recipite de:' + preamble: Illos es predefinite e fortiarte per le moderatores de %{domain}. + preamble_invited: Ante que tu continua, considera le regulas base definite per le moderatores de %{domain}. title: Alcun regulas base. + title_invited: Tu ha essite invitate. security: Securitate set_new_password: Definir un nove contrasigno + setup: + email_below_hint_html: Verifica tu plica de spam, o pete un altero. Tu pote corriger tu adresse email si illo es errate. + email_settings_hint_html: Clicca le ligamine que nos te inviava pro verificar %{email}. + link_not_received: Non obteneva tu un ligamine? + new_confirmation_instructions_sent: Tu recipera un nove email con le ligamine de confirmation in alcun minutas! + title: Verifica tu cassa de ingresso + sign_in: + preamble_html: Accede con tu %{domain} credentiales. Si tu conto es hospite sur un differente servitor, tu non potera authenticar te ci. + title: Acceder a %{domain} + sign_up: + manual_review: Le inscriptiones sur %{domain} passa per revision manual de nostre moderatores. Pro adjutar nos a processar tu registration, scribe un poco re te mesme e perque tu vole un conto sur %{domain}. + preamble: Con un conto sur iste servitor de Mastodon, tu potera sequer ulle altere persona in rete, sin reguardo de ubi lor conto es hospite. + title: Lassa que nos te configura sur %{domain}. status: account_status: Stato del conto + confirming: Attendente esser completate email de confirmation. + functional: Tu conto es plenmente operative. + pending: Tu application es pendente de revision per nostre personal. Isto pote prender alcun tempore. Tu recipera un email si tu application es approbate. + redirecting_to: Tu conto es inactive perque illo es actualmente re-adressa a %{acct}. + self_destruct: Dum %{domain} va clauder, tu solo habera accesso limitate a tu conto. view_strikes: Examinar le admonitiones passate contra tu conto + too_fast: Formulario inviate troppo velocemente, retenta. use_security_key: Usar clave de securitate challenge: confirm: Continuar + hint_html: "Consilio: Nos non te demandara tu contrasigno ancora pro le proxime hora." invalid_password: Contrasigno non valide prompt: Confirma le contrasigno pro continuar + crypto: + errors: + invalid_key: non es un clave Ed25519 o Curve25519 valide + invalid_signature: non es un valide firma Ed25519 + date: + formats: + default: "%b %d, %Y" + with_month_name: "%B %d, %Y" datetime: distance_in_words: + about_x_hours: "%{count}h" + about_x_months: "%{count}me" + about_x_years: "%{count}a" + almost_x_years: "%{count}a" half_a_minute: Justo ora + less_than_x_minutes: "%{count} m" less_than_x_seconds: Justo ora over_x_years: "%{count}a" x_days: "%{count}d" x_minutes: "%{count} m" + x_months: "%{count}me" + x_seconds: "%{count}s" deletes: challenge_not_passed: Le informationes que tu ha inserite non era correcte confirm_password: Insere tu contrasigno actual pro verificar tu identitate @@ -1174,6 +1217,7 @@ ia: download: Discargar tu archivo hint_html: Tu pote requirer un archivo de tu messages e medios cargate. Le datos exportate sera in le formato ActivityPub, legibile per ulle software conforme. in_progress: Compilante tu archivo... + request: Pete tu archivo size: Dimension blocks: Tu ha blocate bookmarks: Marcapaginas @@ -1184,6 +1228,8 @@ ia: storage: Immagazinage de medios featured_tags: add_new: Adder nove + errors: + limit: Tu ha jam consiliate le maxime numero de hashtags filters: contexts: account: Profilos @@ -1196,17 +1242,33 @@ ia: keywords: Parolas clave statuses: Messages individual title: Modificar filtro + errors: + invalid_context: Nulle o non valide contexto supplite index: + contexts: Filtros in %{contexts} delete: Deler + empty: Tu non ha filtros. + expires_in: Expira in %{distance} + expires_on: Expira le %{date} + keywords: + one: "%{count} parola clave" + other: "%{count} parolas clave" statuses: one: "%{count} message" other: "%{count} messages" + statuses_long: + one: "%{count} singule message celate" + other: "%{count} singule messages celate" title: Filtros new: save: Salveguardar nove filtro title: Adder nove filtro statuses: + back_to_filter: Retro al filtro + batch: + remove: Remover ab filtro index: + hint: Iste filtro se applica pro seliger messages singule sin reguardo de altere criterios. Tu pote adder altere messages a iste filtro ab le interfacie web. title: Messages filtrate generic: all: Toto @@ -1215,16 +1277,27 @@ ia: confirm: Confirmar copy: Copiar delete: Deler + deselect: Deseliger toto none: Nemo order_by: Ordinar per save_changes: Salvar le cambios + select_all_matching_items: + one: Selige %{count} elemento concordante tu recerca. + other: Selige %{count} elementos concordante tu recerca. today: hodie + validation_errors: + one: Alco non es multo bon ancora! Controla le error infra + other: Alco non es multo bon ancora! Controla %{count} errores infra imports: errors: empty: File CSV vacue + incompatible_type: Incompatibile con le typo de importation seligite invalid_csv_file: 'File CSV non valide. Error: %{error}' + over_rows_processing_limit: contine plus que %{count} rangos too_large: Le file es troppo longe failures: Fallimentos + imported: Importate + mismatched_types_warning: Il appare que tu pote haber seligite le typo errate pro iste importation, controla duo vices. modes: overwrite_long: Reimplaciar registros actual con le noves overwrite_preambles: @@ -1278,6 +1351,8 @@ ia: max_uses: one: un uso other: "%{count} usos" + table: + expires_at: Expira title: Invitar personas login_activities: authentication_methods: @@ -1316,32 +1391,84 @@ ia: title: Nove requesta de sequimento mention: action: Responder + title: Nove mention poll: subject: Un inquesta de %{name} ha finite otp_authentication: enable: Activar + setup: Configurar pagination: next: Sequente + prev: Previe + truncate: "…" + polls: + errors: + already_voted: Tu jam ha votate in iste sondage + duplicate_options: contine elementos duplicate + duration_too_long: il es troppo lontan in le futuro + duration_too_short: il es troppo tosto + expired: Le sondage ha jam finite + invalid_choice: Le option de voto eligite non existe + over_character_limit: non pote esser plus longe que %{max} characteres cata un + self_vote: Tu non pote vota in tu proprie sondages + too_few_options: debe haber plus que un elemento + too_many_options: non pote continer plus que %{max} elementos preferences: other: Altere + posting_defaults: Publicationes predefinite public_timelines: Chronologias public privacy: privacy: Confidentialitate + reach: Portata search: Cercar + title: Confidentialitate e portata privacy_policy: title: Politica de confidentialitate + reactions: + errors: + limit_reached: Limite de reactiones differente attingite + unrecognized_emoji: non es un emoticone recognoscite + redirects: + prompt: Si tu te fide de iste ligamine, clicca lo pro continuar. + title: Tu va lassar %{instance}. relationships: activity: Activitate del conto + confirm_follow_selected_followers: Desira tu vermente remover le sequaces seligite? + confirm_remove_selected_followers: Desira tu vermente remover le sequaces seligite? + confirm_remove_selected_follows: Desira tu vermente remover le sequaces seligite? + dormant: Dormiente + follow_failure: Impossibile sequer alcun del contos seligite. + follow_selected_followers: Sequer le sequaces seligite + followers: Sequaces + following: Sequente invited: Invitate + last_active: Ultimo active most_recent: Plus recente moved: Movite mutual: Mutue primary: Primari + relationship: Relation + remove_selected_domains: Remover tote le sequaces ab le dominios seligite + remove_selected_followers: Remover le sequaces seligite + remove_selected_follows: Non plus sequer le usatores seligite status: Stato del conto + remote_follow: + missing_resource: Impossibile trovar le requirite re-adresse URL pro tu conto + reports: + errors: + invalid_rules: non referentia regulas valide rss: content_warning: 'Advertimento de contento:' descriptions: account: Messages public de @%{acct} + tag: 'Messages public plachettate #%{hashtag}' + scheduled_statuses: + over_daily_limit: Tu ha excedite le limite de %{limit} messages programmate pro hodie + over_total_limit: Tu ha excedite le limite de %{limit} messages programmate + too_soon: Le data programmate debe esser in le futuro + self_destruct: + lead_html: Infortunatemente, %{domain} va clauder permanentemente. Si tu habeva un conto illac, tu non potera continuar a usar lo, ma tu pote ancora peter un salveguarda de tu datos. + title: Iste servitor va clauder sessions: activity: Ultime activitate browser: Navigator @@ -1368,6 +1495,7 @@ ia: current_session: Session actual date: Data description: "%{browser} sur %{platform}" + explanation: Il ha navigatores del web actualmente connexe a tu conto Mastodon. ip: IP platforms: adobe_air: Adobe Air @@ -1383,11 +1511,16 @@ ia: windows: Windows windows_mobile: Windows Mobile windows_phone: Windows Phone + revoke: Revocar + revoke_success: Session revocate con successo title: Sessiones + view_authentication_history: Vider chronologia de authentication de tu conto settings: account: Conto account_settings: Parametros de conto + aliases: Aliases de conto appearance: Apparentia + authorized_apps: Apps autorisate delete: Deletion de conto development: Disveloppamento edit_profile: Modificar profilo @@ -1417,6 +1550,13 @@ ia: private_long: Solmente monstrar a sequitores public: Public statuses_cleanup: + keep_pinned_hint: Non dele alcuno de tu messages appunctate + keep_polls: Mantener sondages + keep_polls_hint: Non dele ulle de tu sondages + keep_self_bookmark: Mantener messages que tu marcava con marcapaginas + keep_self_bookmark_hint: Non dele tu proprie messages si tu los ha marcate con marcapaginas + keep_self_fav: Mantene messages que tu favoriva + keep_self_fav_hint: Non dele tu proprie messages si tu los ha favorite min_age: '1209600': 2 septimanas '15778476': 6 menses @@ -1426,6 +1566,7 @@ ia: '604800': 1 septimana '63113904': 2 annos '7889238': 3 menses + min_age_label: Limine de etate stream_entries: sensitive_content: Contento sensibile strikes: diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml index 51a3aac273..5e8fd85293 100644 --- a/config/locales/simple_form.cy.yml +++ b/config/locales/simple_form.cy.yml @@ -77,11 +77,13 @@ cy: warn: Cuddiwch y cynnwys wedi'i hidlo y tu ôl i rybudd sy'n sôn am deitl yr hidlydd form_admin_settings: activity_api_enabled: Cyfrif o bostiadau a gyhoeddir yn lleol, defnyddwyr gweithredol, a chofrestriadau newydd mewn bwcedi wythnosol + app_icon: WEBP, PNG, GIF neu JPG. Yn diystyru'r eicon ap rhagosodedig ar ddyfeisiau symudol gydag eicon cyfaddas. backups_retention_period: Mae gan ddefnyddwyr y gallu i gynhyrchu archifau o'u postiadau i'w llwytho i lawr yn ddiweddarach. Pan gânt eu gosod i werth positif, bydd yr archifau hyn yn cael eu dileu'n awtomatig o'ch storfa ar ôl y nifer penodedig o ddyddiau. bootstrap_timeline_accounts: Bydd y cyfrifon hyn yn cael eu pinio i frig argymhellion dilynol defnyddwyr newydd. closed_registrations_message: Yn cael eu dangos pan fydd cofrestriadau wedi cau content_cache_retention_period: Bydd yr holl bostiadau gan weinyddion eraill (gan gynnwys hwb ac atebion) yn cael eu dileu ar ôl y nifer penodedig o ddyddiau, heb ystyried unrhyw ryngweithio defnyddiwr lleol â'r postiadau hynny. Mae hyn yn cynnwys postiadau lle mae defnyddiwr lleol wedi ei farcio fel nodau tudalen neu ffefrynnau. Bydd cyfeiriadau preifat rhwng defnyddwyr o wahanol achosion hefyd yn cael eu colli ac yn amhosibl eu hadfer. Mae'r defnydd o'r gosodiad hwn wedi'i fwriadu ar gyfer achosion pwrpas arbennig ac mae'n torri llawer o ddisgwyliadau defnyddwyr pan gaiff ei weithredu at ddibenion cyffredinol. custom_css: Gallwch gymhwyso arddulliau cyfaddas ar fersiwn gwe Mastodon. + favicon: WEBP, PNG, GIF neu JPG. Yn diystyru'r favicon Mastodon rhagosodedig gydag eicon cyfaddas. mascot: Yn diystyru'r darlun yn y rhyngwyneb gwe uwch. media_cache_retention_period: Mae ffeiliau cyfryngau o bostiadau a wneir gan ddefnyddwyr o bell yn cael eu storio ar eich gweinydd. Pan gaiff ei osod i werth positif, bydd y cyfryngau yn cael eu dileu ar ôl y nifer penodedig o ddyddiau. Os gofynnir am y data cyfryngau ar ôl iddo gael ei ddileu, caiff ei ail-lwytho i lawr, os yw'r cynnwys ffynhonnell yn dal i fod ar gael. Oherwydd cyfyngiadau ar ba mor aml y mae cardiau rhagolwg cyswllt yn pleidleisio i wefannau trydydd parti, argymhellir gosod y gwerth hwn i o leiaf 14 diwrnod, neu ni fydd cardiau rhagolwg cyswllt yn cael eu diweddaru ar alw cyn yr amser hwnnw. peers_api_enabled: Rhestr o enwau parth y mae'r gweinydd hwn wedi dod ar eu traws yn y ffediws. Nid oes unrhyw ddata wedi'i gynnwys yma ynghylch a ydych chi'n ffedereiddio â gweinydd penodol, dim ond bod eich gweinydd yn gwybod amdano. Defnyddir hwn gan wasanaethau sy'n casglu ystadegau ar ffedereiddio mewn ystyr cyffredinol. diff --git a/config/locales/simple_form.en-GB.yml b/config/locales/simple_form.en-GB.yml index f4668ccada..eaf0501a27 100644 --- a/config/locales/simple_form.en-GB.yml +++ b/config/locales/simple_form.en-GB.yml @@ -77,10 +77,15 @@ en-GB: warn: Hide the filtered content behind a warning mentioning the filter's title form_admin_settings: activity_api_enabled: Counts of locally published posts, active users, and new registrations in weekly buckets + app_icon: WEBP, PNG, GIF or JPG. Overrides the default app icon on mobile devices with a custom icon. + backups_retention_period: Users have the ability to generate archives of their posts to download later. When set to a positive value, these archives will be automatically deleted from your storage after the specified number of days. bootstrap_timeline_accounts: These accounts will be pinned to the top of new users' follow recommendations. closed_registrations_message: Displayed when sign-ups are closed + content_cache_retention_period: All posts from other servers (including boosts and replies) will be deleted after the specified number of days, without regard to any local user interaction with those posts. This includes posts where a local user has marked it as bookmarks or favorites. Private mentions between users from different instances will also be lost and impossible to restore. Use of this setting is intended for special purpose instances and breaks many user expectations when implemented for general purpose use. custom_css: You can apply custom styles on the web version of Mastodon. + favicon: WEBP, PNG, GIF or JPG. Overrides the default Mastodon favicon with a custom icon. mascot: Overrides the illustration in the advanced web interface. + media_cache_retention_period: Media files from posts made by remote users are cached on your server. When set to a positive value, media will be deleted after the specified number of days. If the media data is requested after it is deleted, it will be re-downloaded, if the source content is still available. Due to restrictions on how often link preview cards poll third-party sites, it is recommended to set this value to at least 14 days, or link preview cards will not be updated on demand before that time. peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense. profile_directory: The profile directory lists all users who have opted-in to be discoverable. require_invite_text: When sign-ups require manual approval, make the “Why do you want to join?” text input mandatory rather than optional @@ -240,6 +245,7 @@ en-GB: backups_retention_period: User archive retention period bootstrap_timeline_accounts: Always recommend these accounts to new users closed_registrations_message: Custom message when sign-ups are not available + content_cache_retention_period: Remote content retention period custom_css: Custom CSS mascot: Custom mascot (legacy) media_cache_retention_period: Media cache retention period From 6beead38678d6a25adc94ee82ed07974e3e20147 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 15 May 2024 05:33:36 -0400 Subject: [PATCH 162/658] Move `simplecov` config into `rails_helper` (#30302) --- .simplecov | 22 ---------------- config/initializers/simple_cov_source_file.rb | 19 ++++++++++++++ spec/rails_helper.rb | 25 +++++++++++++++++++ spec/spec_helper.rb | 4 --- 4 files changed, 44 insertions(+), 26 deletions(-) delete mode 100644 .simplecov create mode 100644 config/initializers/simple_cov_source_file.rb diff --git a/.simplecov b/.simplecov deleted file mode 100644 index fbd0207bec..0000000000 --- a/.simplecov +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -if ENV['CI'] - require 'simplecov-lcov' - SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true - SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter -else - SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter -end - -SimpleCov.start 'rails' do - enable_coverage :branch - - add_filter 'lib/linter' - - add_group 'Libraries', 'lib' - add_group 'Policies', 'app/policies' - add_group 'Presenters', 'app/presenters' - add_group 'Serializers', 'app/serializers' - add_group 'Services', 'app/services' - add_group 'Validators', 'app/validators' -end diff --git a/config/initializers/simple_cov_source_file.rb b/config/initializers/simple_cov_source_file.rb new file mode 100644 index 0000000000..c6b3586c82 --- /dev/null +++ b/config/initializers/simple_cov_source_file.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# TODO: https://github.com/simplecov-ruby/simplecov/pull/1084 +# Patches this missing condition, monitor for upstream fix + +module SimpleCov + module SourceFileExtensions + def build_branches + coverage_branch_data = coverage_data.fetch('branches', {}) || {} # Add the final empty hash in case where 'branches' is present, but returns nil + branches = coverage_branch_data.flat_map do |condition, coverage_branches| + build_branches_from(condition, coverage_branches) + end + + process_skipped_branches(branches) + end + end +end + +SimpleCov::SourceFile.prepend(SimpleCov::SourceFileExtensions) if defined?(SimpleCov::SourceFile) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d8eb561d42..38aa711089 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -2,6 +2,31 @@ ENV['RAILS_ENV'] ||= 'test' +unless ENV['DISABLE_SIMPLECOV'] == 'true' + require 'simplecov' + + SimpleCov.start 'rails' do + if ENV['CI'] + require 'simplecov-lcov' + formatter SimpleCov::Formatter::LcovFormatter + formatter.config.report_with_single_file = true + else + formatter SimpleCov::Formatter::HTMLFormatter + end + + enable_coverage :branch + + add_filter 'lib/linter' + + add_group 'Libraries', 'lib' + add_group 'Policies', 'app/policies' + add_group 'Presenters', 'app/presenters' + add_group 'Serializers', 'app/serializers' + add_group 'Services', 'app/services' + add_group 'Validators', 'app/validators' + end +end + # This needs to be defined before Rails is initialized STREAMING_PORT = ENV.fetch('TEST_STREAMING_PORT', '4020') ENV['STREAMING_API_BASE_URL'] = "http://localhost:#{STREAMING_PORT}" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8a01792a19..1f9cc40f12 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,9 +1,5 @@ # frozen_string_literal: true -unless ENV['DISABLE_SIMPLECOV'] == 'true' - require 'simplecov' # Configuration details loaded from .simplecov -end - RSpec.configure do |config| config.example_status_persistence_file_path = 'tmp/rspec/examples.txt' config.expect_with :rspec do |expectations| From 85c625d31974e411666812468ddfd7760ab67d4a Mon Sep 17 00:00:00 2001 From: Jason Punyon Date: Wed, 15 May 2024 05:38:16 -0400 Subject: [PATCH 163/658] Fix repetitive database queries from #30040 (#30259) --- app/helpers/application_helper.rb | 13 +++++++++---- app/presenters/instance_presenter.rb | 12 ++++++++++++ app/serializers/manifest_serializer.rb | 2 +- app/views/layouts/application.html.haml | 6 +++--- spec/helpers/application_helper_spec.rb | 15 ++++++++++----- 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ff351429e0..eb03f1e4ba 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -240,11 +240,16 @@ module ApplicationHelper EmojiFormatter.new(html, custom_emojis, other_options.merge(animate: prefers_autoplay?)).to_s end - def site_icon_path(type, size = '48') - icon = SiteUpload.find_by(var: type) - return nil unless icon + def instance_presenter + @instance_presenter ||= InstancePresenter.new + end - icon.file.url(size) + def favicon_path(size = '48') + instance_presenter.favicon&.file&.url(size) + end + + def app_icon_path(size = '48') + instance_presenter.app_icon&.file&.url(size) end private diff --git a/app/presenters/instance_presenter.rb b/app/presenters/instance_presenter.rb index 25df4d85aa..92415a6903 100644 --- a/app/presenters/instance_presenter.rb +++ b/app/presenters/instance_presenter.rb @@ -81,4 +81,16 @@ class InstancePresenter < ActiveModelSerializers::Model def mascot @mascot ||= Rails.cache.fetch('site_uploads/mascot') { SiteUpload.find_by(var: 'mascot') } end + + def favicon + return @favicon if defined?(@favicon) + + @favicon ||= Rails.cache.fetch('site_uploads/favicon') { SiteUpload.find_by(var: 'favicon') } + end + + def app_icon + return @app_icon if defined?(@app_icon) + + @app_icon ||= Rails.cache.fetch('site_uploads/app_icon') { SiteUpload.find_by(var: 'app_icon') } + end end diff --git a/app/serializers/manifest_serializer.rb b/app/serializers/manifest_serializer.rb index 759490228c..a39fb5ef54 100644 --- a/app/serializers/manifest_serializer.rb +++ b/app/serializers/manifest_serializer.rb @@ -27,7 +27,7 @@ class ManifestSerializer < ActiveModel::Serializer def icons SiteUpload::ANDROID_ICON_SIZES.map do |size| - src = site_icon_path('app_icon', size.to_i) + src = app_icon_path(size.to_i) src = URI.join(root_url, src).to_s if src.present? { diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index e3d05226ee..5957d1dbf5 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -11,13 +11,13 @@ - if storage_host? %link{ rel: 'dns-prefetch', href: storage_host }/ - %link{ rel: 'icon', href: site_icon_path('favicon', 'ico') || '/favicon.ico', type: 'image/x-icon' }/ + %link{ rel: 'icon', href: favicon_path('ico') || '/favicon.ico', type: 'image/x-icon' }/ - SiteUpload::FAVICON_SIZES.each do |size| - %link{ rel: 'icon', sizes: "#{size}x#{size}", href: site_icon_path('favicon', size.to_i) || frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/ + %link{ rel: 'icon', sizes: "#{size}x#{size}", href: favicon_path(size.to_i) || frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/ - SiteUpload::APPLE_ICON_SIZES.each do |size| - %link{ rel: 'apple-touch-icon', sizes: "#{size}x#{size}", href: site_icon_path('app_icon', size.to_i) || frontend_asset_path("icons/apple-touch-icon-#{size}x#{size}.png") }/ + %link{ rel: 'apple-touch-icon', sizes: "#{size}x#{size}", href: app_icon_path(size.to_i) || frontend_asset_path("icons/apple-touch-icon-#{size}x#{size}.png") }/ %link{ rel: 'mask-icon', href: frontend_asset_path('images/logo-symbol-icon.svg'), color: '#6364FF' }/ %link{ rel: 'manifest', href: manifest_path(format: :json) }/ diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 56501034b2..56974513be 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -286,26 +286,31 @@ describe ApplicationHelper do end end - describe '#site_icon_path' do + describe 'favicon' do context 'when an icon exists' do let!(:favicon) { Fabricate(:site_upload, var: 'favicon') } + let!(:app_icon) { Fabricate(:site_upload, var: 'app_icon') } it 'returns the URL of the icon' do - expect(helper.site_icon_path('favicon')).to eq(favicon.file.url('48')) + expect(helper.favicon_path).to eq(favicon.file.url('48')) + expect(helper.app_icon_path).to eq(app_icon.file.url('48')) end it 'returns the URL of the icon with size parameter' do - expect(helper.site_icon_path('favicon', 16)).to eq(favicon.file.url('16')) + expect(helper.favicon_path(16)).to eq(favicon.file.url('16')) + expect(helper.app_icon_path(16)).to eq(app_icon.file.url('16')) end end context 'when an icon does not exist' do it 'returns nil' do - expect(helper.site_icon_path('favicon')).to be_nil + expect(helper.favicon_path).to be_nil + expect(helper.app_icon_path).to be_nil end it 'returns nil with size parameter' do - expect(helper.site_icon_path('favicon', 16)).to be_nil + expect(helper.favicon_path(16)).to be_nil + expect(helper.app_icon_path(16)).to be_nil end end end From 4e085dff52f88a4bb81f4f6cbe4c7a37ebfb2390 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 15:05:05 +0200 Subject: [PATCH 164/658] chore(deps): update dependency aws-sdk-s3 to v1.151.0 (#30287) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2854528b73..d34d634f58 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,16 +100,16 @@ GEM attr_required (1.0.2) awrence (1.2.1) aws-eventstream (1.3.0) - aws-partitions (1.922.0) - aws-sdk-core (3.194.1) + aws-partitions (1.929.0) + aws-sdk-core (3.196.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.80.0) + aws-sdk-kms (1.81.0) aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.149.1) + aws-sdk-s3 (1.151.0) aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) From c2ca3d152f1dda0f4f5d2455ae9c550779a2c10e Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 15 May 2024 15:11:13 +0200 Subject: [PATCH 165/658] Fix off-by-one in `tootctl media` commands (#30306) --- lib/mastodon/cli/media.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mastodon/cli/media.rb b/lib/mastodon/cli/media.rb index e26b4f24af..509d11a819 100644 --- a/lib/mastodon/cli/media.rb +++ b/lib/mastodon/cli/media.rb @@ -128,7 +128,7 @@ module Mastodon::CLI model_name = path_segments.first.classify attachment_name = path_segments[1].singularize - record_id = path_segments[2..-2].join.to_i + record_id = path_segments[2...-2].join.to_i file_name = path_segments.last record = record_map.dig(model_name, record_id) attachment = record&.public_send(attachment_name) @@ -172,7 +172,7 @@ module Mastodon::CLI end model_name = path_segments.first.classify - record_id = path_segments[2..-2].join.to_i + record_id = path_segments[2...-2].join.to_i attachment_name = path_segments[1].singularize file_name = path_segments.last @@ -297,7 +297,7 @@ module Mastodon::CLI fail_with_message 'Not a media URL' unless VALID_PATH_SEGMENTS_SIZE.include?(path_segments.size) model_name = path_segments.first.classify - record_id = path_segments[2..-2].join.to_i + record_id = path_segments[2...-2].join.to_i fail_with_message "Cannot find corresponding model: #{model_name}" unless PRELOAD_MODEL_WHITELIST.include?(model_name) @@ -353,7 +353,7 @@ module Mastodon::CLI next unless VALID_PATH_SEGMENTS_SIZE.include?(segments.size) model_name = segments.first.classify - record_id = segments[2..-2].join.to_i + record_id = segments[2...-2].join.to_i next unless PRELOAD_MODEL_WHITELIST.include?(model_name) From 5fd56512de244263b4b0df998b8a83c303c3d1c5 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Wed, 15 May 2024 15:38:36 +0200 Subject: [PATCH 166/658] Improve Report Notes and Account Moderation Notes (#30288) --- app/models/account_moderation_note.rb | 2 +- app/models/report_note.rb | 2 +- app/views/admin/accounts/show.html.haml | 10 ++++---- app/views/admin/reports/show.html.haml | 14 ++++++----- config/navigation.rb | 4 ++-- ...ccount_moderation_notes_controller_spec.rb | 13 ++++++++-- .../admin/report_notes_controller_spec.rb | 24 ++++++++++++++----- 7 files changed, 47 insertions(+), 22 deletions(-) diff --git a/app/models/account_moderation_note.rb b/app/models/account_moderation_note.rb index ad49b24229..79b8b4d25e 100644 --- a/app/models/account_moderation_note.rb +++ b/app/models/account_moderation_note.rb @@ -13,7 +13,7 @@ # class AccountModerationNote < ApplicationRecord - CONTENT_SIZE_LIMIT = 500 + CONTENT_SIZE_LIMIT = 2_000 belongs_to :account belongs_to :target_account, class_name: 'Account' diff --git a/app/models/report_note.rb b/app/models/report_note.rb index b5c40a18b1..7361c97e67 100644 --- a/app/models/report_note.rb +++ b/app/models/report_note.rb @@ -13,7 +13,7 @@ # class ReportNote < ApplicationRecord - CONTENT_SIZE_LIMIT = 500 + CONTENT_SIZE_LIMIT = 2_000 belongs_to :account belongs_to :report, inverse_of: :notes, touch: true diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index 41fcafa29d..bcf7c07314 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -62,14 +62,16 @@ .report-notes = render partial: 'admin/report_notes/report_note', collection: @moderation_notes - = simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f| - = f.hidden_field :target_account_id + = simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |form| + = form.hidden_field :target_account_id + + = render 'shared/error_messages', object: @account_moderation_note .field-group - = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6 + = form.input :content, input_html: { placeholder: t('admin.reports.notes.placeholder'), maxlength: AccountModerationNote::CONTENT_SIZE_LIMIT, rows: 6, autofocus: @account_moderation_note.errors.any? } .actions - = f.button :button, t('admin.account_moderation_notes.create'), type: :submit + = form.button :button, t('admin.account_moderation_notes.create'), type: :submit %hr.spacer/ diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index c880021cff..842aa51597 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -83,15 +83,17 @@ .report-notes = render @report_notes -= simple_form_for @report_note, url: admin_report_notes_path do |f| - = f.input :report_id, as: :hidden += simple_form_for @report_note, url: admin_report_notes_path do |form| + = form.input :report_id, as: :hidden + + = render 'shared/error_messages', object: @report_note .field-group - = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6 + = form.input :content, input_html: { placeholder: t('admin.reports.notes.placeholder'), maxlength: ReportNote::CONTENT_SIZE_LIMIT, rows: 6, autofocus: @report_note.errors.any? } .actions - if @report.unresolved? - = f.button :button, t('admin.reports.notes.create_and_resolve'), name: :create_and_resolve, type: :submit + = form.button :button, t('admin.reports.notes.create_and_resolve'), name: :create_and_resolve, type: :submit - else - = f.button :button, t('admin.reports.notes.create_and_unresolve'), name: :create_and_unresolve, type: :submit - = f.button :button, t('admin.reports.notes.create'), type: :submit + = form.button :button, t('admin.reports.notes.create_and_unresolve'), name: :create_and_unresolve, type: :submit + = form.button :button, t('admin.reports.notes.create'), type: :submit diff --git a/config/navigation.rb b/config/navigation.rb index 791025d526..b6e3f49505 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -45,8 +45,8 @@ SimpleNavigation::Configuration.run do |navigation| end n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) && !self_destruct } do |s| - s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports}, if: -> { current_user.can?(:manage_reports) } - s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) } + s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports|admin/report_notes}, if: -> { current_user.can?(:manage_reports) } + s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|admin/account_moderation_notes|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) } s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) } s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}, if: -> { current_user.can?(:manage_taxonomies) } s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) } diff --git a/spec/controllers/admin/account_moderation_notes_controller_spec.rb b/spec/controllers/admin/account_moderation_notes_controller_spec.rb index 8d24a7af37..5ea546f418 100644 --- a/spec/controllers/admin/account_moderation_notes_controller_spec.rb +++ b/spec/controllers/admin/account_moderation_notes_controller_spec.rb @@ -24,10 +24,19 @@ RSpec.describe Admin::AccountModerationNotesController do end end - context 'when parameters are invalid' do + context 'when the content is too short' do let(:params) { { account_moderation_note: { target_account_id: target_account.id, content: '' } } } - it 'falls to create a note' do + it 'fails to create a note' do + expect { subject }.to_not change(AccountModerationNote, :count) + expect(response).to render_template 'admin/accounts/show' + end + end + + context 'when the content is too long' do + let(:params) { { account_moderation_note: { target_account_id: target_account.id, content: 'test' * AccountModerationNote::CONTENT_SIZE_LIMIT } } } + + it 'fails to create a note' do expect { subject }.to_not change(AccountModerationNote, :count) expect(response).to render_template 'admin/accounts/show' end diff --git a/spec/controllers/admin/report_notes_controller_spec.rb b/spec/controllers/admin/report_notes_controller_spec.rb index 4ddf4a4e24..8d5b5c7aec 100644 --- a/spec/controllers/admin/report_notes_controller_spec.rb +++ b/spec/controllers/admin/report_notes_controller_spec.rb @@ -22,7 +22,7 @@ describe Admin::ReportNotesController do let(:account_id) { nil } context 'when create_and_resolve flag is on' do - let(:params) { { report_note: { content: 'test content', report_id: report.id }, create_and_resolve: nil } } + let(:params) { { report_note: { report_id: report.id, content: 'test content' }, create_and_resolve: nil } } it 'creates a report note and resolves report' do expect { subject }.to change(ReportNote, :count).by(1) @@ -32,7 +32,7 @@ describe Admin::ReportNotesController do end context 'when create_and_resolve flag is false' do - let(:params) { { report_note: { content: 'test content', report_id: report.id } } } + let(:params) { { report_note: { report_id: report.id, content: 'test content' } } } it 'creates a report note and does not resolve report' do expect { subject }.to change(ReportNote, :count).by(1) @@ -47,7 +47,7 @@ describe Admin::ReportNotesController do let(:account_id) { user.account.id } context 'when create_and_unresolve flag is on' do - let(:params) { { report_note: { content: 'test content', report_id: report.id }, create_and_unresolve: nil } } + let(:params) { { report_note: { report_id: report.id, content: 'test content' }, create_and_unresolve: nil } } it 'creates a report note and unresolves report' do expect { subject }.to change(ReportNote, :count).by(1) @@ -57,7 +57,7 @@ describe Admin::ReportNotesController do end context 'when create_and_unresolve flag is false' do - let(:params) { { report_note: { content: 'test content', report_id: report.id } } } + let(:params) { { report_note: { report_id: report.id, content: 'test content' } } } it 'creates a report note and does not unresolve report' do expect { subject }.to change(ReportNote, :count).by(1) @@ -68,12 +68,24 @@ describe Admin::ReportNotesController do end end - context 'when parameter is invalid' do - let(:params) { { report_note: { content: '', report_id: report.id } } } + context 'when content is too short' do + let(:params) { { report_note: { report_id: report.id, content: '' } } } let(:action_taken) { nil } let(:account_id) { nil } it 'renders admin/reports/show' do + expect { subject }.to_not change(ReportNote, :count) + expect(subject).to render_template 'admin/reports/show' + end + end + + context 'when content is too long' do + let(:params) { { report_note: { report_id: report.id, content: 'test' * ReportNote::CONTENT_SIZE_LIMIT } } } + let(:action_taken) { nil } + let(:account_id) { nil } + + it 'renders admin/reports/show' do + expect { subject }.to_not change(ReportNote, :count) expect(subject).to render_template 'admin/reports/show' end end From d5d3a0fc57ff712061a3bd18736d68851f04f86c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 15:38:51 +0200 Subject: [PATCH 167/658] fix(deps): update dependency pino to v9.1.0 (#30283) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3741a54195..3d85014d49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13042,13 +13042,6 @@ __metadata: languageName: node linkType: hard -"pino-std-serializers@npm:^6.0.0": - version: 6.2.2 - resolution: "pino-std-serializers@npm:6.2.2" - checksum: 10c0/8f1c7f0f0d8f91e6c6b5b2a6bfb48f06441abeb85f1c2288319f736f9c6d814fbeebe928d2314efc2ba6018fa7db9357a105eca9fc99fc1f28945a8a8b28d3d5 - languageName: node - linkType: hard - "pino-std-serializers@npm:^7.0.0": version: 7.0.0 resolution: "pino-std-serializers@npm:7.0.0" @@ -13057,23 +13050,23 @@ __metadata: linkType: hard "pino@npm:^9.0.0": - version: 9.0.0 - resolution: "pino@npm:9.0.0" + version: 9.1.0 + resolution: "pino@npm:9.1.0" dependencies: atomic-sleep: "npm:^1.0.0" fast-redact: "npm:^3.1.1" on-exit-leak-free: "npm:^2.1.0" pino-abstract-transport: "npm:^1.2.0" - pino-std-serializers: "npm:^6.0.0" + pino-std-serializers: "npm:^7.0.0" process-warning: "npm:^3.0.0" quick-format-unescaped: "npm:^4.0.3" real-require: "npm:^0.2.0" safe-stable-stringify: "npm:^2.3.1" - sonic-boom: "npm:^3.7.0" - thread-stream: "npm:^2.6.0" + sonic-boom: "npm:^4.0.1" + thread-stream: "npm:^3.0.0" bin: pino: bin.js - checksum: 10c0/10ef10aee0cf80af8ed83468cff2e29d642b6794b53cf641e1abcaf9e9958d8bcbc6e09d62757054aef3b4415c45d66a5018da11d43b81a23ba299ef5dc4e8b1 + checksum: 10c0/d060530ae2e4e8f21d04bb0f44f009f94d207d7f4337f508f618416514214ddaf1b29f8c5c265153a19ce3b6480b451461f40020f916ace9d53a5aa07624b79c languageName: node linkType: hard @@ -15822,7 +15815,7 @@ __metadata: languageName: node linkType: hard -"sonic-boom@npm:^3.0.0, sonic-boom@npm:^3.7.0": +"sonic-boom@npm:^3.0.0": version: 3.7.0 resolution: "sonic-boom@npm:3.7.0" dependencies: @@ -15831,6 +15824,15 @@ __metadata: languageName: node linkType: hard +"sonic-boom@npm:^4.0.1": + version: 4.0.1 + resolution: "sonic-boom@npm:4.0.1" + dependencies: + atomic-sleep: "npm:^1.0.0" + checksum: 10c0/7b467f2bc8af7ff60bf210382f21c59728cc4b769af9b62c31dd88723f5cc472752d2320736cc366acc7c765ddd5bec3072c033b0faf249923f576a7453ba9d3 + languageName: node + linkType: hard + "source-list-map@npm:^2.0.0": version: 2.0.1 resolution: "source-list-map@npm:2.0.1" @@ -16776,12 +16778,12 @@ __metadata: languageName: node linkType: hard -"thread-stream@npm:^2.6.0": - version: 2.6.0 - resolution: "thread-stream@npm:2.6.0" +"thread-stream@npm:^3.0.0": + version: 3.0.0 + resolution: "thread-stream@npm:3.0.0" dependencies: real-require: "npm:^0.2.0" - checksum: 10c0/276e2545b33273232eb2c22c53fc11844951c1322f8a78c522477af716ebcfe0d106ccf1fbc455f6e48d928e93231fed6377ce91fdcb3885086e8ffa1f011c88 + checksum: 10c0/1f4da5a8c93b170cdc7c1ad774af49bb2af43f73cfd9a7f8fb02b766255b483eb6d0b734502c880397baa95c0ce3490088b9a487cff32d4e481aab6fe76560f5 languageName: node linkType: hard From ca560c10958d3ad96736c974c778380c2adacef2 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 15 May 2024 09:57:13 -0400 Subject: [PATCH 168/658] Disable `Style/RedundantFetchBlock` cop (#30207) --- .rubocop.yml | 5 +++++ .rubocop_todo.yml | 10 ---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 542e90b5e3..cbc0afd281 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -211,6 +211,11 @@ Style/PercentLiteralDelimiters: Style/RedundantBegin: Enabled: false +# Reason: Prevailing style choice +# https://docs.rubocop.org/rubocop/cops_style.html#styleredundantfetchblock +Style/RedundantFetchBlock: + Enabled: false + # Reason: Overridden to reduce implicit StandardError rescues # https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror Style/RescueStandardError: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b47d682f3e..064f622085 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -169,16 +169,6 @@ Style/RedundantConstantBase: - 'config/environments/production.rb' - 'config/initializers/sidekiq.rb' -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: SafeForConstants. -Style/RedundantFetchBlock: - Exclude: - - 'config/initializers/1_hosts.rb' - - 'config/initializers/chewy.rb' - - 'config/initializers/devise.rb' - - 'config/initializers/paperclip.rb' - - 'config/puma.rb' - # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. # AllowedMethods: present?, blank?, presence, try, try! From 94493cff925ee9b9cb4ebc7cc20081ab20521b85 Mon Sep 17 00:00:00 2001 From: David Lapshin Date: Thu, 16 May 2024 10:33:29 +0300 Subject: [PATCH 169/658] Fix incorrect element selector from #30221 (#30307) --- app/javascript/styles/mastodon/components.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 927c57d990..f377eed95c 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -4365,10 +4365,6 @@ a.status-card { outline: $ui-button-focus-outline; } - .no-reduce-motion .icon { - transition: transform 0.15s ease-in-out; - } - &.active { color: $primary-text-color; @@ -4387,6 +4383,10 @@ a.status-card { } } +.no-reduce-motion .column-header__button .icon { + transition: transform 150ms ease-in-out; +} + .column-header__collapsible { max-height: 70vh; overflow: hidden; From 60b423b3f72feea31e0d22b02b948848819ad601 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 09:43:31 +0200 Subject: [PATCH 170/658] chore(deps): update dependency rspec-sidekiq to v5 (#30314) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index b9baef7036..240dcce95a 100644 --- a/Gemfile +++ b/Gemfile @@ -132,7 +132,7 @@ group :test do gem 'email_spec' # Extra RSpec extension methods and helpers for sidekiq - gem 'rspec-sidekiq', '~> 4.0' + gem 'rspec-sidekiq', '~> 5.0' # Browser integration testing gem 'capybara', '~> 3.39' diff --git a/Gemfile.lock b/Gemfile.lock index d34d634f58..a20ac79aea 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -708,7 +708,7 @@ GEM rspec-support (~> 3.13.0) rspec-github (2.4.0) rspec-core (~> 3.0) - rspec-mocks (3.13.0) + rspec-mocks (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-rails (6.1.2) @@ -719,7 +719,7 @@ GEM rspec-expectations (~> 3.13) rspec-mocks (~> 3.13) rspec-support (~> 3.13) - rspec-sidekiq (4.2.0) + rspec-sidekiq (5.0.0) rspec-core (~> 3.0) rspec-expectations (~> 3.0) rspec-mocks (~> 3.0) @@ -1012,7 +1012,7 @@ DEPENDENCIES rqrcode (~> 2.2) rspec-github (~> 2.4) rspec-rails (~> 6.0) - rspec-sidekiq (~> 4.0) + rspec-sidekiq (~> 5.0) rubocop rubocop-capybara rubocop-performance From c9ee1437c0a12bea5fbafb7efbb8e87e4eb6fe0e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 16 May 2024 03:43:35 -0400 Subject: [PATCH 171/658] Use ruby language constants to build version string in software version dimension (#30309) --- .../admin/metrics/dimension/software_versions_dimension.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/lib/admin/metrics/dimension/software_versions_dimension.rb b/app/lib/admin/metrics/dimension/software_versions_dimension.rb index ccf556eae0..97cdaf589e 100644 --- a/app/lib/admin/metrics/dimension/software_versions_dimension.rb +++ b/app/lib/admin/metrics/dimension/software_versions_dimension.rb @@ -25,14 +25,11 @@ class Admin::Metrics::Dimension::SoftwareVersionsDimension < Admin::Metrics::Dim end def ruby_version - yjit = defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? - value = "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}#{yjit ? ' +YJIT' : ''}" - { key: 'ruby', human_key: 'Ruby', - value: value, - human_value: value, + value: "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}", + human_value: RUBY_DESCRIPTION, } end From cdb042ae860c79d47920f30a3ba8b7625e7de56d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 09:50:19 +0200 Subject: [PATCH 172/658] New Crowdin Translations (automated) (#30319) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/gl.json | 2 +- app/javascript/mastodon/locales/sk.json | 3 ++- app/javascript/mastodon/locales/tr.json | 2 +- config/locales/sk.yml | 15 +++++++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 88d4f5f60e..98cc313948 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -92,7 +92,7 @@ "block_modal.remote_users_caveat": "Ímoslle pedir ao servidor {domain} que respecte a túa decisión. Emporiso, non hai garantía de que atenda a petición xa que os servidores xestionan os bloqueos de formas diferentes. As publicacións públicas poderían aínda ser visibles para usuarias que non iniciaron sesión.", "block_modal.show_less": "Mostrar menos", "block_modal.show_more": "Mostrar máis", - "block_modal.they_cant_mention": "Non te pode seguir nin mencionar.", + "block_modal.they_cant_mention": "Non te poden seguir nin mencionar.", "block_modal.they_cant_see_posts": "Non pode ver as túas publicacións nin ti as de ela.", "block_modal.they_will_know": "Pode ver que a bloqueaches.", "block_modal.title": "Bloquear usuaria?", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 0c76467419..c583b58220 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -295,7 +295,7 @@ "follow_suggestions.personalized_suggestion": "Prispôsobený návrh", "follow_suggestions.popular_suggestion": "Obľúbený návrh", "follow_suggestions.popular_suggestion_longer": "Populárne na {domain}", - "follow_suggestions.similar_to_recently_followed_longer": "Podobné profilom ktoré si nedávno nasledoval/a", + "follow_suggestions.similar_to_recently_followed_longer": "Podobné profilom, ktoré si nedávno nasledoval/a", "follow_suggestions.view_all": "Zobraziť všetky", "follow_suggestions.who_to_follow": "Koho sledovať", "followed_tags": "Sledované hashtagy", @@ -446,6 +446,7 @@ "notification.follow_request": "{name} vás žiada sledovať", "notification.mention": "{name} vás spomína", "notification.moderation-warning.learn_more": "Zisti viac", + "notification.moderation_warning.action_disable": "Tvoj účet bol vypnutý.", "notification.moderation_warning.action_silence": "Tvoj účet bol obmedzený.", "notification.moderation_warning.action_suspend": "Tvoj účet bol pozastavený.", "notification.own_poll": "Vaša anketa sa skončila", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index c46080cfb2..6c01106593 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -474,7 +474,7 @@ "notification.follow_request": "{name} size takip isteği gönderdi", "notification.mention": "{name} senden bahsetti", "notification.moderation-warning.learn_more": "Daha fazlası", - "notification.moderation_warning": "Bir denetim uyarısı aldınız", + "notification.moderation_warning": "Hesabınız bir denetim uyarısı aldı", "notification.moderation_warning.action_delete_statuses": "Bazı gönderileriniz kaldırıldı.", "notification.moderation_warning.action_disable": "Hesabınız devre dışı bırakıldı.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Bazı gönderileriniz hassas olarak işaretlendi.", diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 78e7bdb25e..f05887dc33 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -254,9 +254,12 @@ sk: destroy_status_html: "%{name} zmazal/a príspevok od %{target}" destroy_unavailable_domain_html: "%{name} znova spustil/a doručovanie pre doménu %{target}" destroy_user_role_html: "%{name} vymazal/a rolu pre %{target}" + enable_custom_emoji_html: "%{name} povolil/a emotikonu %{target}" 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" + promote_user_html: "%{name} povýšil/a užívateľa %{target}" reject_appeal_html: "%{name} zamietol/la námietku moderovacieho rozhodnutia od %{target}" + reject_user_html: "%{name} odmietol/la registráciu 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}" @@ -266,7 +269,9 @@ sk: 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}" + unblock_email_account_html: "%{name} odblokoval/a %{target}ovu/inu emailovú adresu" unsensitive_account_html: "%{name} odznačil/a médium od %{target} ako chúlostivé" + unsilence_account_html: "%{name} zrušil/a obmedzenie %{target}ovho/inho účtu" 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}" @@ -529,6 +534,9 @@ sk: actions: suspend_description_html: Tento účet a všetok jeho obsah bude nedostupný a nakoniec zmazaný, interaktovať s ním bude nemožné. Zvrátiteľné v rámci 30 dní. Uzatvára všetky hlásenia voči tomuto účtu. add_to_report: Pridaj viac do hlásenia + already_suspended_badges: + local: Na tomto serveri už vylúčený/á + remote: Už vylúčený/á na ich serveri are_you_sure: Si si istý/á? assign_to_self: Priraď sebe assigned: Priradený moderátor @@ -538,6 +546,7 @@ sk: comment: none: Žiadne confirm: Potvrď + confirm_action: Potvrď moderovací úkon proti @%{acct} created_at: Nahlásené delete_and_resolve: Vymaž príspevky forwarded: Preposlané @@ -592,8 +601,14 @@ sk: delete: Vymaž edit: Uprav postavenie %{name} everyone: Východzie oprávnenia + permissions_count: + few: "%{count} povolení" + many: "%{count} povolení" + one: "%{count} povolenie" + other: "%{count} povolenia" privileges: administrator: Správca + administrator_description: Užívatelia s týmto povolením, obídu všetky povolenia delete_user_data: Vymaž užívateľské dáta invite_users: Pozvi užívateľov manage_announcements: Spravuj oboznámenia From 356bbbaa7f903b7849af1bb78a7954c250c00d46 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 09:57:19 +0200 Subject: [PATCH 173/658] fix(deps): update dependency @reduxjs/toolkit to v2.2.5 (#30320) 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 3d85014d49..07c89a5298 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3050,8 +3050,8 @@ __metadata: linkType: hard "@reduxjs/toolkit@npm:^2.0.1": - version: 2.2.4 - resolution: "@reduxjs/toolkit@npm:2.2.4" + version: 2.2.5 + resolution: "@reduxjs/toolkit@npm:2.2.5" dependencies: immer: "npm:^10.0.3" redux: "npm:^5.0.1" @@ -3065,7 +3065,7 @@ __metadata: optional: true react-redux: optional: true - checksum: 10c0/fdbf510210a5aa4864432397e1a9469367e297cd1d9c09a82e68638df7555672c2f8511fe76f933b00efbbb233c534831591772a44e8c41233e34f3cd0f54569 + checksum: 10c0/be0593bf26852482fb8716b9248531466c6e8782a3114b823ae680fce90267d8c5512a3231cfecc30b17eff81a4604112772b49ad7ca6a3366ddd4f2a838e53c languageName: node linkType: hard From f0d6dc4519cc0311583f139834fbbbcd64e82d7a Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Thu, 16 May 2024 09:59:46 +0200 Subject: [PATCH 174/658] Fix: Mark redirect uris field in Development > Application form as required (#30311) --- app/controllers/settings/applications_controller.rb | 2 +- app/views/settings/applications/_fields.html.haml | 1 + config/navigation.rb | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/settings/applications_controller.rb b/app/controllers/settings/applications_controller.rb index d4b7205681..6849979b11 100644 --- a/app/controllers/settings/applications_controller.rb +++ b/app/controllers/settings/applications_controller.rb @@ -13,7 +13,7 @@ class Settings::ApplicationsController < Settings::BaseController def new @application = Doorkeeper::Application.new( redirect_uri: Doorkeeper.configuration.native_redirect_uri, - scopes: 'read write follow' + scopes: 'read:me' ) end diff --git a/app/views/settings/applications/_fields.html.haml b/app/views/settings/applications/_fields.html.haml index ed97e880fc..d539848952 100644 --- a/app/views/settings/applications/_fields.html.haml +++ b/app/views/settings/applications/_fields.html.haml @@ -11,6 +11,7 @@ .fields-group = f.input :redirect_uri, label: t('activerecord.attributes.doorkeeper/application.redirect_uri'), hint: t('doorkeeper.applications.help.redirect_uri'), + required: true, wrapper: :with_block_label %p.hint= t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: content_tag(:code, Doorkeeper.configuration.native_redirect_uri)).html_safe diff --git a/config/navigation.rb b/config/navigation.rb index b6e3f49505..efac96d46e 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -36,7 +36,7 @@ SimpleNavigation::Configuration.run do |navigation| end n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? && !self_destruct } - n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, if: -> { current_user.functional? && !self_destruct } + n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, highlights_on: %r{/settings/applications}, if: -> { current_user.functional? && !self_destruct } n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) && !self_destruct } do |s| s.item :statuses, safe_join([fa_icon('comments-o fw'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses} From 65e82211cdaffa3132832dc42756913d668985c3 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 16 May 2024 04:03:46 -0400 Subject: [PATCH 175/658] Rename `cache_*` methods to `preload_*` in controller concern (#30209) --- app/controllers/accounts_controller.rb | 2 +- .../activitypub/collections_controller.rb | 2 +- .../activitypub/outboxes_controller.rb | 2 +- .../api/v1/accounts/statuses_controller.rb | 6 +++--- app/controllers/api/v1/bookmarks_controller.rb | 6 +++--- app/controllers/api/v1/favourites_controller.rb | 6 +++--- .../api/v1/notifications/requests_controller.rb | 2 +- .../api/v1/notifications_controller.rb | 2 +- app/controllers/api/v1/statuses_controller.rb | 8 ++++---- .../api/v1/timelines/home_controller.rb | 6 +++--- .../api/v1/timelines/list_controller.rb | 6 +++--- .../api/v1/timelines/public_controller.rb | 6 +++--- .../api/v1/timelines/tag_controller.rb | 6 +++--- .../api/v1/trends/statuses_controller.rb | 2 +- app/controllers/application_controller.rb | 1 + app/controllers/concerns/cache_concern.rb | 16 ---------------- app/controllers/concerns/preloading_concern.rb | 17 +++++++++++++++++ app/controllers/tags_controller.rb | 2 +- ...ncern_spec.rb => preloading_concern_spec.rb} | 12 ++++++------ 19 files changed, 56 insertions(+), 54 deletions(-) create mode 100644 app/controllers/concerns/preloading_concern.rb rename spec/controllers/concerns/{cache_concern_spec.rb => preloading_concern_spec.rb} (79%) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 32549e1516..c3131edce9 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -25,7 +25,7 @@ class AccountsController < ApplicationController limit = params[:limit].present? ? [params[:limit].to_i, PAGE_SIZE_MAX].min : PAGE_SIZE @statuses = filtered_statuses.without_reblogs.limit(limit) - @statuses = cache_collection(@statuses, Status) + @statuses = preload_collection(@statuses, Status) end format.json do diff --git a/app/controllers/activitypub/collections_controller.rb b/app/controllers/activitypub/collections_controller.rb index d5632902fe..c25362c9bc 100644 --- a/app/controllers/activitypub/collections_controller.rb +++ b/app/controllers/activitypub/collections_controller.rb @@ -18,7 +18,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController def set_items case params[:id] when 'featured' - @items = for_signed_account { cache_collection(@account.pinned_statuses, Status) } + @items = for_signed_account { preload_collection(@account.pinned_statuses, Status) } @items = @items.map { |item| item.distributable? ? item : ActivityPub::TagManager.instance.uri_for(item) } when 'tags' @items = for_signed_account { @account.featured_tags } diff --git a/app/controllers/activitypub/outboxes_controller.rb b/app/controllers/activitypub/outboxes_controller.rb index 8079e011dd..b8baf64e1a 100644 --- a/app/controllers/activitypub/outboxes_controller.rb +++ b/app/controllers/activitypub/outboxes_controller.rb @@ -60,7 +60,7 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController def set_statuses return unless page_requested? - @statuses = cache_collection_paginated_by_id( + @statuses = preload_collection_paginated_by_id( AccountStatusesFilter.new(@account, signed_request_account).results, Status, LIMIT, diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb index 35ea9c8ec1..c42f27776c 100644 --- a/app/controllers/api/v1/accounts/statuses_controller.rb +++ b/app/controllers/api/v1/accounts/statuses_controller.rb @@ -19,11 +19,11 @@ class Api::V1::Accounts::StatusesController < Api::BaseController end def load_statuses - @account.unavailable? ? [] : cached_account_statuses + @account.unavailable? ? [] : preloaded_account_statuses end - def cached_account_statuses - cache_collection_paginated_by_id( + def preloaded_account_statuses + preload_collection_paginated_by_id( AccountStatusesFilter.new(@account, current_account, params).results, Status, limit_param(DEFAULT_STATUSES_LIMIT), diff --git a/app/controllers/api/v1/bookmarks_controller.rb b/app/controllers/api/v1/bookmarks_controller.rb index b6bb987b6b..f7671a9032 100644 --- a/app/controllers/api/v1/bookmarks_controller.rb +++ b/app/controllers/api/v1/bookmarks_controller.rb @@ -13,11 +13,11 @@ class Api::V1::BookmarksController < Api::BaseController private def load_statuses - cached_bookmarks + preloaded_bookmarks end - def cached_bookmarks - cache_collection(results.map(&:status), Status) + def preloaded_bookmarks + preload_collection(results.map(&:status), Status) end def results diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb index 73da538f5c..18ca9ab866 100644 --- a/app/controllers/api/v1/favourites_controller.rb +++ b/app/controllers/api/v1/favourites_controller.rb @@ -13,11 +13,11 @@ class Api::V1::FavouritesController < Api::BaseController private def load_statuses - cached_favourites + preloaded_favourites end - def cached_favourites - cache_collection(results.map(&:status), Status) + def preloaded_favourites + preload_collection(results.map(&:status), Status) end def results diff --git a/app/controllers/api/v1/notifications/requests_controller.rb b/app/controllers/api/v1/notifications/requests_controller.rb index 6a26cc0e8a..0e58379a38 100644 --- a/app/controllers/api/v1/notifications/requests_controller.rb +++ b/app/controllers/api/v1/notifications/requests_controller.rb @@ -41,7 +41,7 @@ class Api::V1::Notifications::RequestsController < Api::BaseController ) NotificationRequest.preload_cache_collection(requests) do |statuses| - cache_collection(statuses, Status) + preload_collection(statuses, Status) end end diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb index c41a0bb05d..1d0aa10d2e 100644 --- a/app/controllers/api/v1/notifications_controller.rb +++ b/app/controllers/api/v1/notifications_controller.rb @@ -41,7 +41,7 @@ class Api::V1::NotificationsController < Api::BaseController ) Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses| - cache_collection(target_statuses, Status) + preload_collection(target_statuses, Status) end end diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 36a9ec6325..5f7e66617d 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -26,13 +26,13 @@ class Api::V1::StatusesController < Api::BaseController DESCENDANTS_DEPTH_LIMIT = 20 def index - @statuses = cache_collection(@statuses, Status) + @statuses = preload_collection(@statuses, Status) render json: @statuses, each_serializer: REST::StatusSerializer end def show cache_if_unauthenticated! - @status = cache_collection([@status], Status).first + @status = preload_collection([@status], Status).first render json: @status, serializer: REST::StatusSerializer end @@ -51,8 +51,8 @@ class Api::V1::StatusesController < Api::BaseController ancestors_results = @status.in_reply_to_id.nil? ? [] : @status.ancestors(ancestors_limit, current_account) descendants_results = @status.descendants(descendants_limit, current_account, descendants_depth_limit) - loaded_ancestors = cache_collection(ancestors_results, Status) - loaded_descendants = cache_collection(descendants_results, Status) + loaded_ancestors = preload_collection(ancestors_results, Status) + loaded_descendants = preload_collection(descendants_results, Status) @context = Context.new(ancestors: loaded_ancestors, descendants: loaded_descendants) statuses = [@status] + @context.ancestors + @context.descendants diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb index 36fdbea647..d5d1828666 100644 --- a/app/controllers/api/v1/timelines/home_controller.rb +++ b/app/controllers/api/v1/timelines/home_controller.rb @@ -21,11 +21,11 @@ class Api::V1::Timelines::HomeController < Api::V1::Timelines::BaseController private def load_statuses - cached_home_statuses + preloaded_home_statuses end - def cached_home_statuses - cache_collection home_statuses, Status + def preloaded_home_statuses + preload_collection home_statuses, Status end def home_statuses diff --git a/app/controllers/api/v1/timelines/list_controller.rb b/app/controllers/api/v1/timelines/list_controller.rb index 14b884ecd9..d8cdbdb74c 100644 --- a/app/controllers/api/v1/timelines/list_controller.rb +++ b/app/controllers/api/v1/timelines/list_controller.rb @@ -21,11 +21,11 @@ class Api::V1::Timelines::ListController < Api::V1::Timelines::BaseController end def set_statuses - @statuses = cached_list_statuses + @statuses = preloaded_list_statuses end - def cached_list_statuses - cache_collection list_statuses, Status + def preloaded_list_statuses + preload_collection list_statuses, Status end def list_statuses diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb index 35af8dc4b5..d164854d6a 100644 --- a/app/controllers/api/v1/timelines/public_controller.rb +++ b/app/controllers/api/v1/timelines/public_controller.rb @@ -18,11 +18,11 @@ class Api::V1::Timelines::PublicController < Api::V1::Timelines::BaseController end def load_statuses - cached_public_statuses_page + preloaded_public_statuses_page end - def cached_public_statuses_page - cache_collection(public_statuses, Status) + def preloaded_public_statuses_page + preload_collection(public_statuses, Status) end def public_statuses diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb index 4ba439dbb2..3bf8f374e1 100644 --- a/app/controllers/api/v1/timelines/tag_controller.rb +++ b/app/controllers/api/v1/timelines/tag_controller.rb @@ -23,11 +23,11 @@ class Api::V1::Timelines::TagController < Api::V1::Timelines::BaseController end def load_statuses - cached_tagged_statuses + preloaded_tagged_statuses end - def cached_tagged_statuses - @tag.nil? ? [] : cache_collection(tag_timeline_statuses, Status) + def preloaded_tagged_statuses + @tag.nil? ? [] : preload_collection(tag_timeline_statuses, Status) end def tag_timeline_statuses diff --git a/app/controllers/api/v1/trends/statuses_controller.rb b/app/controllers/api/v1/trends/statuses_controller.rb index 48bfe11991..c6fbbce167 100644 --- a/app/controllers/api/v1/trends/statuses_controller.rb +++ b/app/controllers/api/v1/trends/statuses_controller.rb @@ -20,7 +20,7 @@ class Api::V1::Trends::StatusesController < Api::BaseController def set_statuses @statuses = if enabled? - cache_collection(statuses_from_trends.offset(offset_param).limit(limit_param(DEFAULT_STATUSES_LIMIT)), Status) + preload_collection(statuses_from_trends.offset(offset_param).limit(limit_param(DEFAULT_STATUSES_LIMIT)), Status) else [] end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 8ba10d64c0..66e0f7e305 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -9,6 +9,7 @@ class ApplicationController < ActionController::Base include UserTrackingConcern include SessionTrackingConcern include CacheConcern + include PreloadingConcern include DomainControlHelper include DatabaseHelper include AuthorizedFetchHelper diff --git a/app/controllers/concerns/cache_concern.rb b/app/controllers/concerns/cache_concern.rb index 4656539f85..1823b5b8ed 100644 --- a/app/controllers/concerns/cache_concern.rb +++ b/app/controllers/concerns/cache_concern.rb @@ -45,20 +45,4 @@ module CacheConcern Rails.cache.write(key, response.body, expires_in: expires_in, raw: true) end end - - # TODO: Rename this method, as it does not perform any caching anymore. - def cache_collection(raw, klass) - return raw unless klass.respond_to?(:preload_cacheable_associations) - - records = raw.to_a - - klass.preload_cacheable_associations(records) - - records - end - - # TODO: Rename this method, as it does not perform any caching anymore. - def cache_collection_paginated_by_id(raw, klass, limit, options) - cache_collection raw.to_a_paginated_by_id(limit, options), klass - end end diff --git a/app/controllers/concerns/preloading_concern.rb b/app/controllers/concerns/preloading_concern.rb new file mode 100644 index 0000000000..61e2213649 --- /dev/null +++ b/app/controllers/concerns/preloading_concern.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module PreloadingConcern + extend ActiveSupport::Concern + + def preload_collection(scope, klass) + return scope unless klass.respond_to?(:preload_cacheable_associations) + + scope.to_a.tap do |records| + klass.preload_cacheable_associations(records) + end + end + + def preload_collection_paginated_by_id(scope, klass, limit, options) + preload_collection scope.to_a_paginated_by_id(limit, options), klass + end +end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index b0bdbde956..d6c0d872c8 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -45,7 +45,7 @@ class TagsController < ApplicationController end def set_statuses - @statuses = cache_collection(TagFeed.new(@tag, nil, local: @local).get(limit_param), Status) + @statuses = preload_collection(TagFeed.new(@tag, nil, local: @local).get(limit_param), Status) end def limit_param diff --git a/spec/controllers/concerns/cache_concern_spec.rb b/spec/controllers/concerns/preloading_concern_spec.rb similarity index 79% rename from spec/controllers/concerns/cache_concern_spec.rb rename to spec/controllers/concerns/preloading_concern_spec.rb index fffd2b266e..795afbc45e 100644 --- a/spec/controllers/concerns/cache_concern_spec.rb +++ b/spec/controllers/concerns/preloading_concern_spec.rb @@ -2,20 +2,20 @@ require 'rails_helper' -RSpec.describe CacheConcern do +RSpec.describe PreloadingConcern do controller(ApplicationController) do - include CacheConcern + include PreloadingConcern def empty_array - render plain: cache_collection([], Status).size + render plain: preload_collection([], Status).size end def empty_relation - render plain: cache_collection(Status.none, Status).size + render plain: preload_collection(Status.none, Status).size end def account_statuses_favourites - render plain: cache_collection(Status.where(account_id: params[:id]), Status).map(&:favourites_count) + render plain: preload_collection(Status.where(account_id: params[:id]), Status).map(&:favourites_count) end end @@ -27,7 +27,7 @@ RSpec.describe CacheConcern do end end - describe '#cache_collection' do + describe '#preload_collection' do context 'when given an empty array' do it 'returns an empty array' do get :empty_array From 283a891e9290fc9fdbfd082f3bde48863f1c6f45 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 16 May 2024 11:28:10 +0200 Subject: [PATCH 176/658] Allow to customise the OTEL service name prefix (#30322) --- config/initializers/opentelemetry.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/initializers/opentelemetry.rb b/config/initializers/opentelemetry.rb index e50132d461..9af0ab89c8 100644 --- a/config/initializers/opentelemetry.rb +++ b/config/initializers/opentelemetry.rb @@ -53,10 +53,12 @@ if ENV.keys.any? { |name| name.match?(/OTEL_.*_ENDPOINT/) } }, }) + prefix = ENV.fetch('OTEL_SERVICE_NAME_PREFIX', 'mastodon') + c.service_name = case $PROGRAM_NAME - when /puma/ then 'mastodon/web' + when /puma/ then "#{prefix}/web" else - "mastodon/#{$PROGRAM_NAME.split('/').last}" + "#{prefix}/#{$PROGRAM_NAME.split('/').last}" end c.service_version = Mastodon::Version.to_s end From 1b6eb2c7f0425a20f9bd823419138bf8adfa18f4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 16 May 2024 05:56:48 -0400 Subject: [PATCH 177/658] Enable YJIT when available (#30310) --- config/initializers/enable_yjit.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 config/initializers/enable_yjit.rb diff --git a/config/initializers/enable_yjit.rb b/config/initializers/enable_yjit.rb new file mode 100644 index 0000000000..7b1053ec11 --- /dev/null +++ b/config/initializers/enable_yjit.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Automatically enable YJIT as of Ruby 3.3, as it brings very +# sizeable performance improvements. + +# If you are deploying to a memory constrained environment +# you may want to delete this file, but otherwise it's free +# performance. +if defined?(RubyVM::YJIT.enable) + Rails.application.config.after_initialize do + RubyVM::YJIT.enable + end +end From 66906a1bc1fb3934dc101e1d8d7ec4a9ce54a12e Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 16 May 2024 15:01:01 +0200 Subject: [PATCH 178/658] Fix Web UI trying to save user settings when logged out (#30324) --- app/javascript/mastodon/actions/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/actions/settings.js b/app/javascript/mastodon/actions/settings.js index 3685b0684e..fbd89f9d4b 100644 --- a/app/javascript/mastodon/actions/settings.js +++ b/app/javascript/mastodon/actions/settings.js @@ -20,7 +20,7 @@ export function changeSetting(path, value) { } const debouncedSave = debounce((dispatch, getState) => { - if (getState().getIn(['settings', 'saved'])) { + if (getState().getIn(['settings', 'saved']) || !getState().getIn(['meta', 'me'])) { return; } From b2388be71eb0031ef9e47c492b1c038231cd8bc0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 15:45:17 +0200 Subject: [PATCH 179/658] chore(deps): update dependency selenium-webdriver to v4.21.0 (#30325) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a20ac79aea..6001c73db4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -693,7 +693,8 @@ GEM responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.2.6) + rexml (3.2.8) + strscan (>= 3.0.9) rotp (6.3.0) rouge (4.2.1) rpam2 (4.0.2) @@ -774,7 +775,7 @@ GEM scenic (1.8.0) activerecord (>= 4.0.0) railties (>= 4.0.0) - selenium-webdriver (4.20.1) + selenium-webdriver (4.21.0) base64 (~> 0.2) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) @@ -815,6 +816,7 @@ GEM stringio (3.1.0) strong_migrations (1.8.0) activerecord (>= 5.2) + strscan (3.1.0) swd (1.3.0) activesupport (>= 3) attr_required (>= 0.0.5) From 061464a563eb05538adaa992a02a8d17d99af099 Mon Sep 17 00:00:00 2001 From: David Lapshin Date: Thu, 16 May 2024 10:33:29 +0300 Subject: [PATCH 180/658] [Glitch] Fix incorrect element selector from #30221 Port 94493cff925ee9b9cb4ebc7cc20081ab20521b85 to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/styles/components.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 6e06898d84..9f102b847e 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -4602,10 +4602,6 @@ a.status-card { outline: $ui-button-focus-outline; } - .no-reduce-motion .icon { - transition: transform 0.15s ease-in-out; - } - &.active { color: $primary-text-color; @@ -4663,6 +4659,10 @@ a.status-card { padding: 0; } +.no-reduce-motion .column-header__button .icon { + transition: transform 150ms ease-in-out; +} + .column-header__collapsible { max-height: 70vh; overflow: hidden; From 7b078b46a2951f9c8548c26528a46abc4e5e6f3c Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 16 May 2024 15:01:01 +0200 Subject: [PATCH 181/658] [Glitch] Fix Web UI trying to save user settings when logged out Port 66906a1bc1fb3934dc101e1d8d7ec4a9ce54a12e to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/actions/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/flavours/glitch/actions/settings.js b/app/javascript/flavours/glitch/actions/settings.js index 3685b0684e..fbd89f9d4b 100644 --- a/app/javascript/flavours/glitch/actions/settings.js +++ b/app/javascript/flavours/glitch/actions/settings.js @@ -20,7 +20,7 @@ export function changeSetting(path, value) { } const debouncedSave = debounce((dispatch, getState) => { - if (getState().getIn(['settings', 'saved'])) { + if (getState().getIn(['settings', 'saved']) || !getState().getIn(['meta', 'me'])) { return; } From 226d7a7badf0d03f2c2a57fd4da72889a3563d28 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 10:27:03 +0200 Subject: [PATCH 182/658] fix(deps): update dependency sass to v1.77.2 (#30338) 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 07c89a5298..db706f04a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15316,15 +15316,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.77.1 - resolution: "sass@npm:1.77.1" + version: 1.77.2 + resolution: "sass@npm:1.77.2" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/edcfc7d038234b1198c3ddcac5963fcd1e17a9c1ee0f9bd09784ab5353b60ff50b189b4c9154b34f5da9ca0eaab8b189fd3e83a4b43a494151ad4735f8e5f364 + checksum: 10c0/0d292339064de3c902e209d41de9c4eb2038cff326476aeebbb5be3eee1d23400d975face2b8e124ae617b10af3e93bec01580f61912f34e4c517fe137a118b6 languageName: node linkType: hard From f7f5b9dadd9e2cee98bf8a7d41193844a37c662b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 08:27:45 +0000 Subject: [PATCH 183/658] fix(deps): update dependency @rails/ujs to v7.1.3-3 (#30337) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 79544229df..773f19c50d 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "@formatjs/intl-pluralrules": "^5.2.2", "@gamestdio/websocket": "^0.3.2", "@github/webauthn-json": "^2.1.1", - "@rails/ujs": "7.1.3-2", + "@rails/ujs": "7.1.3-3", "@reduxjs/toolkit": "^2.0.1", "@svgr/webpack": "^5.5.0", "arrow-key-navigation": "^1.2.0", diff --git a/yarn.lock b/yarn.lock index db706f04a7..efe8cc0264 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2758,7 +2758,7 @@ __metadata: "@formatjs/intl-pluralrules": "npm:^5.2.2" "@gamestdio/websocket": "npm:^0.3.2" "@github/webauthn-json": "npm:^2.1.1" - "@rails/ujs": "npm:7.1.3-2" + "@rails/ujs": "npm:7.1.3-3" "@reduxjs/toolkit": "npm:^2.0.1" "@svgr/webpack": "npm:^5.5.0" "@testing-library/jest-dom": "npm:^6.0.0" @@ -3042,10 +3042,10 @@ __metadata: languageName: node linkType: hard -"@rails/ujs@npm:7.1.3-2": - version: 7.1.3-2 - resolution: "@rails/ujs@npm:7.1.3-2" - checksum: 10c0/8bd5b3a409c62f53790ed7e914f1f48235f461a472da7b4ce1d9ad57356fcdeaa7891c946298f7f620ff0ff7c6d5b995bf44057929c4fce796867a8cf4f27c99 +"@rails/ujs@npm:7.1.3-3": + version: 7.1.3-3 + resolution: "@rails/ujs@npm:7.1.3-3" + checksum: 10c0/9eee95372b72d8f704b67f14a3bf9f2681ab5b11c7b79919bfde3341f2970771876af5b40de5b3e4fca6a97c76a41046eff71d96490617c1fc80ef3ad8bbac47 languageName: node linkType: hard From 3286ad5226ca220a40f12353df2237c4f822af1d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 10:28:01 +0200 Subject: [PATCH 184/658] chore(deps): update dependency selenium-webdriver to v4.21.1 (#30335) 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 6001c73db4..2f46655549 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -775,7 +775,7 @@ GEM scenic (1.8.0) activerecord (>= 4.0.0) railties (>= 4.0.0) - selenium-webdriver (4.21.0) + selenium-webdriver (4.21.1) base64 (~> 0.2) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) From fc166d07f0b5472866e1e13a0c12d78a0c7bbcfb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 10:28:22 +0200 Subject: [PATCH 185/658] chore(deps): update dependency rails to v7.1.3.3 (#30334) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 108 +++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2f46655549..eade99acfd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,35 +10,35 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + actioncable (7.1.3.3) + actionpack (= 7.1.3.3) + activesupport (= 7.1.3.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionmailbox (7.1.3.3) + actionpack (= 7.1.3.3) + activejob (= 7.1.3.3) + activerecord (= 7.1.3.3) + activestorage (= 7.1.3.3) + activesupport (= 7.1.3.3) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.3.2) - actionpack (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionmailer (7.1.3.3) + actionpack (= 7.1.3.3) + actionview (= 7.1.3.3) + activejob (= 7.1.3.3) + activesupport (= 7.1.3.3) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.3.2) - actionview (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionpack (7.1.3.3) + actionview (= 7.1.3.3) + activesupport (= 7.1.3.3) nokogiri (>= 1.8.5) racc rack (>= 2.2.4) @@ -46,15 +46,15 @@ GEM rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.2) - actionpack (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + actiontext (7.1.3.3) + actionpack (= 7.1.3.3) + activerecord (= 7.1.3.3) + activestorage (= 7.1.3.3) + activesupport (= 7.1.3.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.2) - activesupport (= 7.1.3.2) + actionview (7.1.3.3) + activesupport (= 7.1.3.3) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) @@ -64,22 +64,22 @@ GEM activemodel (>= 4.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.1.3.2) - activesupport (= 7.1.3.2) + activejob (7.1.3.3) + activesupport (= 7.1.3.3) globalid (>= 0.3.6) - activemodel (7.1.3.2) - activesupport (= 7.1.3.2) - activerecord (7.1.3.2) - activemodel (= 7.1.3.2) - activesupport (= 7.1.3.2) + activemodel (7.1.3.3) + activesupport (= 7.1.3.3) + activerecord (7.1.3.3) + activemodel (= 7.1.3.3) + activesupport (= 7.1.3.3) timeout (>= 0.4.0) - activestorage (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activesupport (= 7.1.3.2) + activestorage (7.1.3.3) + actionpack (= 7.1.3.3) + activejob (= 7.1.3.3) + activerecord (= 7.1.3.3) + activesupport (= 7.1.3.3) marcel (~> 1.0) - activesupport (7.1.3.2) + activesupport (7.1.3.3) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -444,7 +444,7 @@ GEM timeout net-smtp (0.5.0) net-protocol - nio4r (2.7.1) + nio4r (2.7.3) nokogiri (1.16.5) mini_portile2 (~> 2.8.2) racc (~> 1.4) @@ -634,20 +634,20 @@ GEM rackup (1.0.0) rack (< 3) webrick - rails (7.1.3.2) - actioncable (= 7.1.3.2) - actionmailbox (= 7.1.3.2) - actionmailer (= 7.1.3.2) - actionpack (= 7.1.3.2) - actiontext (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activemodel (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + rails (7.1.3.3) + actioncable (= 7.1.3.3) + actionmailbox (= 7.1.3.3) + actionmailer (= 7.1.3.3) + actionpack (= 7.1.3.3) + actiontext (= 7.1.3.3) + actionview (= 7.1.3.3) + activejob (= 7.1.3.3) + activemodel (= 7.1.3.3) + activerecord (= 7.1.3.3) + activestorage (= 7.1.3.3) + activesupport (= 7.1.3.3) bundler (>= 1.15.0) - railties (= 7.1.3.2) + railties (= 7.1.3.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -662,9 +662,9 @@ GEM rails-i18n (7.0.9) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + railties (7.1.3.3) + actionpack (= 7.1.3.3) + activesupport (= 7.1.3.3) irb rackup (>= 1.0.0) rake (>= 12.2) From a6d12299f22e0318f0bea8b4a0192e6c07398b70 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 17 May 2024 04:29:13 -0400 Subject: [PATCH 186/658] Remove duplicate method def `ApplicationHelper#instance_presenter` (#30331) --- app/helpers/application_helper.rb | 4 ++++ app/helpers/mascot_helper.rb | 11 ----------- app/mailers/user_mailer.rb | 1 - 3 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 app/helpers/mascot_helper.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index eb03f1e4ba..7563ae6105 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -240,6 +240,10 @@ module ApplicationHelper EmojiFormatter.new(html, custom_emojis, other_options.merge(animate: prefers_autoplay?)).to_s end + def mascot_url + full_asset_url(instance_presenter.mascot&.file&.url || frontend_asset_path('images/elephant_ui_plane.svg')) + end + def instance_presenter @instance_presenter ||= InstancePresenter.new end diff --git a/app/helpers/mascot_helper.rb b/app/helpers/mascot_helper.rb deleted file mode 100644 index 34b656411e..0000000000 --- a/app/helpers/mascot_helper.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module MascotHelper - def mascot_url - full_asset_url(instance_presenter.mascot&.file&.url || frontend_asset_path('images/elephant_ui_plane.svg')) - end - - def instance_presenter - @instance_presenter ||= InstancePresenter.new - end -end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index f8c1c9a8d0..81a2c0c6d0 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -5,7 +5,6 @@ class UserMailer < Devise::Mailer helper :accounts helper :application - helper :mascot helper :formatting helper :instance helper :routing From bff7769f5f9a4f3995038ad759c1b48a636d303b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 10:41:35 +0200 Subject: [PATCH 187/658] New Crowdin Translations (automated) (#30336) Co-authored-by: GitHub Actions --- config/locales/simple_form.fi.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml index 4971e25022..2f7010bacf 100644 --- a/config/locales/simple_form.fi.yml +++ b/config/locales/simple_form.fi.yml @@ -81,9 +81,11 @@ fi: backups_retention_period: Käyttäjillä on mahdollisuus arkistoida julkaisujaan myöhemmin ladattaviksi. Kun tämä on asetettu positiiviseksi arvoksi, nämä arkistot poistetaan automaattisesti asetetun päivien määrän jälkeen. bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuosituslistojen alkuun. closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu + content_cache_retention_period: Kaikki muiden palvelimien viestit (mukaan lukien tehostukset ja vastaukset) poistetaan määritetyn päivien lukumäärän jälkeen, ottamatta huomioon paikallisen käyttäjän vuorovaikutusta kyseisten viestien kanssa. Sisältää viestit, jossa paikallinen käyttäjä on merkinnyt kirjanmerkiksi tai suosikeiksi. Myös yksityiset maininnat eri käyttäjien välillä menetetään, eikä niitä voi palauttaa. Tämän asetuksen käyttö on tarkoitettu erityisiin tapauksiin ja se rikkoo monia käyttäjien odotuksia, kun se toteutetaan yleistarkoituksiin. custom_css: Voit käyttää mukautettuja tyylejä Mastodonin verkkoversiossa. favicon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen Mastodonin suosikkikuvakkeen omalla kuvakkeella. mascot: Ohittaa kuvituksen edistyneessä selainkäyttöliittymässä. + media_cache_retention_period: Mediatiedostot käyttäjien tekemistä viesteistä ovat välimuistissa palvelimellasi. Kun arvo on positiivinen, media poistetaan määritetyn ajan jälkeen. Jos mediaa pyydetään sen poistamisen jälkeen, ne ladataan uudelleen, jos lähdesisältö on vielä saatavilla. Koska linkkien katselun kyselyitä kolmansien osapuolien sivustoille on rajoitettu, on suositeltavaa asettaa tämä arvo vähintään 14 päivään tai linkkien kortteja ei päivitetä pyynnöstä ennen tätä aikaa. peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, oletko liitossa tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja federoinnista yleisellä tasolla. profile_directory: Profiilihakemisto lueteloi kaikki käyttäjät, jotka ovat ilmoittaneet olevansa löydettävissä. require_invite_text: Kun rekisteröityminen vaatii manuaalisen hyväksynnän, tee ”Miksi haluat liittyä?” -tekstikentästä pakollinen vapaaehtoisen sijaan From a627219b25f1787cbee0174e37e36e440489eb66 Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Fri, 17 May 2024 18:18:54 +0900 Subject: [PATCH 188/658] Fix moderation action logs (#30342) --- app/models/admin/action_log_filter.rb | 1 + config/locales/en.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/models/admin/action_log_filter.rb b/app/models/admin/action_log_filter.rb index f581af74e8..fc984b2445 100644 --- a/app/models/admin/action_log_filter.rb +++ b/app/models/admin/action_log_filter.rb @@ -59,6 +59,7 @@ class Admin::ActionLogFilter unsuspend_account: { target_type: 'Account', action: 'unsuspend' }.freeze, update_announcement: { target_type: 'Announcement', action: 'update' }.freeze, update_custom_emoji: { target_type: 'CustomEmoji', action: 'update' }.freeze, + update_report: { target_type: 'Report', action: 'update' }.freeze, update_status: { target_type: 'Status', action: 'update' }.freeze, update_user_role: { target_type: 'UserRole', action: 'update' }.freeze, update_ip_block: { target_type: 'IpBlock', action: 'update' }.freeze, diff --git a/config/locales/en.yml b/config/locales/en.yml index 446d06f0d1..d3704bbbcf 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -285,6 +285,7 @@ en: update_custom_emoji_html: "%{name} updated emoji %{target}" update_domain_block_html: "%{name} updated domain block for %{target}" update_ip_block_html: "%{name} changed rule for IP %{target}" + update_report_html: "%{name} updated report %{target}" update_status_html: "%{name} updated post by %{target}" update_user_role_html: "%{name} changed %{target} role" deleted_account: deleted account From 12472e7f407c42bcff6ee204b9f1887b5824734f Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 17 May 2024 11:28:40 +0200 Subject: [PATCH 189/658] Add emphasis on ActiveRecord Encryption configuration values being secret (#30340) --- .env.test | 9 +++++---- config/initializers/active_record_encryption.rb | 13 +++++++++++-- lib/tasks/db.rake | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.env.test b/.env.test index 9e6abea5c9..d2763e582a 100644 --- a/.env.test +++ b/.env.test @@ -4,7 +4,8 @@ NODE_ENV=production LOCAL_DOMAIN=cb6e6126.ngrok.io LOCAL_HTTPS=true -# Required by ActiveRecord encryption feature -ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=fkSxKD2bF396kdQbrP1EJ7WbU7ZgNokR -ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=r0hvVmzBVsjxC7AMlwhOzmtc36ZCOS1E -ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=PhdFyyfy5xJ7WVd2lWBpcPScRQHzRTNr +# Secret values required by ActiveRecord encryption feature +# Use `bin/rails db:encryption:init` to generate fresh secrets +ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=test_determinist_key_DO_NOT_USE_IN_PRODUCTION +ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=test_salt_DO_NOT_USE_IN_PRODUCTION +ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=test_primary_key_DO_NOT_USE_IN_PRODUCTION diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb index 7cda8c621c..777bafc273 100644 --- a/config/initializers/active_record_encryption.rb +++ b/config/initializers/active_record_encryption.rb @@ -5,7 +5,7 @@ ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY ).each do |key| - ENV.fetch(key) do + value = ENV.fetch(key) do abort <<~MESSAGE Mastodon now requires that these variables are set: @@ -14,9 +14,18 @@ - ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT - ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY - Run `bin/rails db:encryption:init` to generate values and then assign the environment variables. + Run `bin/rails db:encryption:init` to generate new secrets and then assign the environment variables. MESSAGE end + + next unless Rails.env.production? && value.end_with?('DO_NOT_USE_IN_PRODUCTION') + + abort <<~MESSAGE + + It looks like you are trying to run Mastodon in production with a #{key} value from the test environment. + + Please generate fresh secrets using `bin/rails db:encryption:init` and use them instead. + MESSAGE end Rails.application.configure do diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index d6377c9c82..d8bc927bc4 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -8,7 +8,7 @@ namespace :db do desc 'Generate a set of keys for configuring Active Record encryption in a given environment' task :init do # rubocop:disable Rails/RakeEnvironment puts <<~MSG - Add these environment variables to your Mastodon environment:#{' '} + Add these secret environment variables to your Mastodon environment (e.g. .env.production):#{' '} ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=#{SecureRandom.alphanumeric(32)} ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=#{SecureRandom.alphanumeric(32)} From 2da2a1dae984f4083d1cc2f55642811c696955e6 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Fri, 17 May 2024 15:46:12 +0200 Subject: [PATCH 190/658] Support multiple redirect_uris when creating OAuth 2.0 Applications (#29192) --- .../api/v1/apps/credentials_controller.rb | 2 +- app/controllers/api/v1/apps_controller.rb | 4 +- app/lib/application_extension.rb | 6 + .../rest/application_serializer.rb | 14 +- .../rest/credential_application_serializer.rb | 13 ++ spec/requests/api/v1/apps/credentials_spec.rb | 23 ++- spec/requests/api/v1/apps_spec.rb | 164 +++++++++++++++++- 7 files changed, 201 insertions(+), 25 deletions(-) create mode 100644 app/serializers/rest/credential_application_serializer.rb diff --git a/app/controllers/api/v1/apps/credentials_controller.rb b/app/controllers/api/v1/apps/credentials_controller.rb index 6256bed64c..29ab920383 100644 --- a/app/controllers/api/v1/apps/credentials_controller.rb +++ b/app/controllers/api/v1/apps/credentials_controller.rb @@ -4,6 +4,6 @@ class Api::V1::Apps::CredentialsController < Api::BaseController def show return doorkeeper_render_error unless valid_doorkeeper_token? - render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key client_id scopes) + render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer end end diff --git a/app/controllers/api/v1/apps_controller.rb b/app/controllers/api/v1/apps_controller.rb index 97177547a2..50feaf1854 100644 --- a/app/controllers/api/v1/apps_controller.rb +++ b/app/controllers/api/v1/apps_controller.rb @@ -5,7 +5,7 @@ class Api::V1::AppsController < Api::BaseController def create @app = Doorkeeper::Application.create!(application_options) - render json: @app, serializer: REST::ApplicationSerializer + render json: @app, serializer: REST::CredentialApplicationSerializer end private @@ -24,6 +24,6 @@ class Api::V1::AppsController < Api::BaseController end def app_params - params.permit(:client_name, :redirect_uris, :scopes, :website) + params.permit(:client_name, :scopes, :website, :redirect_uris, redirect_uris: []) end end diff --git a/app/lib/application_extension.rb b/app/lib/application_extension.rb index 400c51a023..2fea1057cb 100644 --- a/app/lib/application_extension.rb +++ b/app/lib/application_extension.rb @@ -23,6 +23,12 @@ module ApplicationExtension redirect_uri.lines.first.strip end + def redirect_uris + # Doorkeeper stores the redirect_uri value as a newline delimeted list in + # the database: + redirect_uri.split + end + def push_to_streaming_api # TODO: #28793 Combine into a single topic payload = Oj.dump(event: :kill) diff --git a/app/serializers/rest/application_serializer.rb b/app/serializers/rest/application_serializer.rb index 635508a17c..1a7b9265f1 100644 --- a/app/serializers/rest/application_serializer.rb +++ b/app/serializers/rest/application_serializer.rb @@ -1,24 +1,18 @@ # frozen_string_literal: true class REST::ApplicationSerializer < ActiveModel::Serializer - attributes :id, :name, :website, :scopes, :redirect_uri, - :client_id, :client_secret + attributes :id, :name, :website, :scopes, :redirect_uris # NOTE: Deprecated in 4.3.0, needs to be removed in 5.0.0 attribute :vapid_key + # We should consider this property deprecated for 4.3.0 + attribute :redirect_uri + def id object.id.to_s end - def client_id - object.uid - end - - def client_secret - object.secret - end - def website object.website.presence end diff --git a/app/serializers/rest/credential_application_serializer.rb b/app/serializers/rest/credential_application_serializer.rb new file mode 100644 index 0000000000..bfec7d03e8 --- /dev/null +++ b/app/serializers/rest/credential_application_serializer.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class REST::CredentialApplicationSerializer < REST::ApplicationSerializer + attributes :client_id, :client_secret + + def client_id + object.uid + end + + def client_secret + object.secret + end +end diff --git a/spec/requests/api/v1/apps/credentials_spec.rb b/spec/requests/api/v1/apps/credentials_spec.rb index e1455fe799..6e6970ce53 100644 --- a/spec/requests/api/v1/apps/credentials_spec.rb +++ b/spec/requests/api/v1/apps/credentials_spec.rb @@ -20,14 +20,26 @@ describe 'Credentials' do expect(body_as_json).to match( a_hash_including( + id: token.application.id.to_s, name: token.application.name, website: token.application.website, - vapid_key: Rails.configuration.x.vapid_public_key, scopes: token.application.scopes.map(&:to_s), - client_id: token.application.uid + redirect_uris: token.application.redirect_uris, + # Deprecated properties as of 4.3: + redirect_uri: token.application.redirect_uri.split.first, + vapid_key: Rails.configuration.x.vapid_public_key ) ) end + + it 'does not expose the client_id or client_secret' do + subject + + expect(response).to have_http_status(200) + + expect(body_as_json[:client_id]).to_not be_present + expect(body_as_json[:client_secret]).to_not be_present + end end context 'with a non-read scoped oauth token' do @@ -46,11 +58,14 @@ describe 'Credentials' do expect(body_as_json).to match( a_hash_including( + id: token.application.id.to_s, name: token.application.name, website: token.application.website, - vapid_key: Rails.configuration.x.vapid_public_key, scopes: token.application.scopes.map(&:to_s), - client_id: token.application.uid + redirect_uris: token.application.redirect_uris, + # Deprecated properties as of 4.3: + redirect_uri: token.application.redirect_uri.split.first, + vapid_key: Rails.configuration.x.vapid_public_key ) ) end diff --git a/spec/requests/api/v1/apps_spec.rb b/spec/requests/api/v1/apps_spec.rb index acabbc93f0..1f01bddf3c 100644 --- a/spec/requests/api/v1/apps_spec.rb +++ b/spec/requests/api/v1/apps_spec.rb @@ -9,8 +9,9 @@ RSpec.describe 'Apps' do end let(:client_name) { 'Test app' } - let(:scopes) { nil } - let(:redirect_uris) { 'urn:ietf:wg:oauth:2.0:oob' } + let(:scopes) { 'read write' } + let(:redirect_uri) { 'urn:ietf:wg:oauth:2.0:oob' } + let(:redirect_uris) { [redirect_uri] } let(:website) { nil } let(:params) do @@ -26,13 +27,63 @@ RSpec.describe 'Apps' do it 'creates an OAuth app', :aggregate_failures do subject + expect(response).to have_http_status(200) + + app = Doorkeeper::Application.find_by(name: client_name) + + expect(app).to be_present + expect(app.scopes.to_s).to eq scopes + expect(app.redirect_uris).to eq redirect_uris + + expect(body_as_json).to match( + a_hash_including( + id: app.id.to_s, + client_id: app.uid, + client_secret: app.secret, + name: client_name, + website: website, + scopes: ['read', 'write'], + redirect_uris: redirect_uris, + # Deprecated properties as of 4.3: + redirect_uri: redirect_uri, + vapid_key: Rails.configuration.x.vapid_public_key + ) + ) + end + end + + context 'without scopes being supplied' do + let(:scopes) { nil } + + it 'creates an OAuth App with the default scope' do + subject + expect(response).to have_http_status(200) expect(Doorkeeper::Application.find_by(name: client_name)).to be_present body = body_as_json - expect(body[:client_id]).to be_present - expect(body[:client_secret]).to be_present + expect(body[:scopes]).to eq Doorkeeper.config.default_scopes.to_a + end + end + + # FIXME: This is a bug: https://github.com/mastodon/mastodon/issues/30152 + context 'with scopes as an array' do + let(:scopes) { %w(read write follow) } + + it 'creates an OAuth App with the default scope' do + subject + + expect(response).to have_http_status(200) + + app = Doorkeeper::Application.find_by(name: client_name) + + expect(app).to be_present + expect(app.scopes.to_s).to eq 'read' + + body = body_as_json + + expect(body[:scopes]).to eq ['read'] end end @@ -77,8 +128,8 @@ RSpec.describe 'Apps' do end end - context 'with a too-long redirect_uris' do - let(:redirect_uris) { "https://foo.bar/#{'hoge' * 2_000}" } + context 'with a too-long redirect_uri' do + let(:redirect_uris) { "https://app.example/#{'hoge' * 2_000}" } it 'returns http unprocessable entity' do subject @@ -87,8 +138,80 @@ RSpec.describe 'Apps' do end end - context 'without required params' do - let(:client_name) { '' } + # NOTE: This spec currently tests the same as the "with a too-long redirect_uri test case" + context 'with too many redirect_uris' do + let(:redirect_uris) { (0...500).map { |i| "https://app.example/#{i}/callback" } } + + it 'returns http unprocessable entity' do + subject + + expect(response).to have_http_status(422) + end + end + + context 'with multiple redirect_uris as a string' do + let(:redirect_uris) { "https://redirect1.example/\napp://redirect2.example/" } + + it 'creates an OAuth application with multiple redirect URIs' do + subject + + expect(response).to have_http_status(200) + + app = Doorkeeper::Application.find_by(name: client_name) + + expect(app).to be_present + expect(app.redirect_uri).to eq redirect_uris + expect(app.redirect_uris).to eq redirect_uris.split + + body = body_as_json + + expect(body[:redirect_uri]).to eq redirect_uris + expect(body[:redirect_uris]).to eq redirect_uris.split + end + end + + context 'with multiple redirect_uris as an array' do + let(:redirect_uris) { ['https://redirect1.example/', 'app://redirect2.example/'] } + + it 'creates an OAuth application with multiple redirect URIs' do + subject + + expect(response).to have_http_status(200) + + app = Doorkeeper::Application.find_by(name: client_name) + + expect(app).to be_present + expect(app.redirect_uri).to eq redirect_uris.join "\n" + expect(app.redirect_uris).to eq redirect_uris + + body = body_as_json + + expect(body[:redirect_uri]).to eq redirect_uris.join "\n" + expect(body[:redirect_uris]).to eq redirect_uris + end + end + + context 'with an empty redirect_uris array' do + let(:redirect_uris) { [] } + + it 'returns http unprocessable entity' do + subject + + expect(response).to have_http_status(422) + end + end + + context 'with just a newline as the redirect_uris string' do + let(:redirect_uris) { "\n" } + + it 'returns http unprocessable entity' do + subject + + expect(response).to have_http_status(422) + end + end + + context 'with an empty redirect_uris string' do let(:redirect_uris) { '' } it 'returns http unprocessable entity' do @@ -97,5 +220,30 @@ RSpec.describe 'Apps' do expect(response).to have_http_status(422) end end + + context 'without a required param' do + let(:client_name) { '' } + + it 'returns http unprocessable entity' do + subject + + expect(response).to have_http_status(422) + end + end + + context 'with a website' do + let(:website) { 'https://app.example/' } + + it 'creates an OAuth application with the website specified' do + subject + + expect(response).to have_http_status(200) + + app = Doorkeeper::Application.find_by(name: client_name) + + expect(app).to be_present + expect(app.website).to eq website + end + end end end From 6282b6da7753b0feaafd9d15e12bbc8dd6958c8f Mon Sep 17 00:00:00 2001 From: Joshua Byrd Date: Mon, 20 May 2024 02:30:05 +1000 Subject: [PATCH 191/658] Fix og:image requests when html in a web page is over 1.megabyte (#30362) --- app/services/fetch_link_card_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index c6b600dd7c..36e866b6ce 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -56,7 +56,7 @@ class FetchLinkCardService < BaseService @html_charset = res.charset - res.body_with_limit + res.truncated_body end end From a178ba7cd5fa10b018ecaf3c8e3dd5f298a08818 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Sun, 19 May 2024 19:07:32 +0200 Subject: [PATCH 192/658] Use a modern React context for identity in the app (#30098) --- .../mastodon/components/column_header.jsx | 12 ++- app/javascript/mastodon/components/poll.jsx | 11 +-- .../mastodon/components/status_action_bar.jsx | 17 ++--- .../mastodon/components/status_content.jsx | 12 ++- .../mastodon/containers/mastodon.jsx | 52 ++++--------- .../features/account/components/header.jsx | 10 +-- .../features/community_timeline/index.jsx | 13 ++-- .../features/compose/components/search.jsx | 13 ++-- .../mastodon/features/explore/index.jsx | 11 +-- .../mastodon/features/firehose/index.jsx | 12 +-- .../features/getting_started/index.jsx | 13 ++-- .../features/hashtag_timeline/index.jsx | 15 ++-- .../mastodon/features/home_timeline/index.jsx | 11 +-- .../components/column_settings.jsx | 15 ++-- .../mastodon/features/notifications/index.jsx | 11 +-- .../picture_in_picture/components/footer.jsx | 15 ++-- .../features/public_timeline/index.jsx | 13 ++-- .../features/status/components/action_bar.jsx | 11 +-- .../mastodon/features/status/index.jsx | 15 ++-- .../features/ui/components/compose_panel.jsx | 11 +-- .../features/ui/components/header.jsx | 11 +-- .../features/ui/components/link_footer.jsx | 11 +-- .../ui/components/navigation_panel.jsx | 11 +-- app/javascript/mastodon/features/ui/index.jsx | 25 +++---- app/javascript/mastodon/identity_context.tsx | 74 +++++++++++++++++++ app/javascript/mastodon/initial_state.js | 10 +++ 26 files changed, 212 insertions(+), 223 deletions(-) create mode 100644 app/javascript/mastodon/identity_context.tsx diff --git a/app/javascript/mastodon/components/column_header.jsx b/app/javascript/mastodon/components/column_header.jsx index a7d07ffdb0..42183f336d 100644 --- a/app/javascript/mastodon/components/column_header.jsx +++ b/app/javascript/mastodon/components/column_header.jsx @@ -14,8 +14,10 @@ import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import SettingsIcon from '@/material-icons/400-24px/settings.svg?react'; import { Icon } from 'mastodon/components/icon'; import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; + import { useAppHistory } from './router'; const messages = defineMessages({ @@ -51,12 +53,8 @@ BackButton.propTypes = { }; class ColumnHeader extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, title: PropTypes.node, icon: PropTypes.string, @@ -171,7 +169,7 @@ class ColumnHeader extends PureComponent { ); } - if (this.context.identity.signedIn && (children || (multiColumn && this.props.onPin))) { + if (this.props.identity.signedIn && (children || (multiColumn && this.props.onPin))) { collapseButton = ( } + {!showResults && } {!showResults && <> · } {showResults && !this.props.disabled && <> · } {votesCount} @@ -247,4 +244,4 @@ class Poll extends ImmutablePureComponent { } -export default injectIntl(Poll); +export default injectIntl(withIdentity(Poll)); diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 6def49fdbb..c79eae8460 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -22,6 +22,7 @@ import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react'; import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react'; import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react'; import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; @@ -74,12 +75,8 @@ const mapStateToProps = (state, { status }) => ({ }); class StatusActionBar extends ImmutablePureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, status: ImmutablePropTypes.map.isRequired, relationship: ImmutablePropTypes.record, onReply: PropTypes.func, @@ -118,7 +115,7 @@ class StatusActionBar extends ImmutablePureComponent { ]; handleReplyClick = () => { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { this.props.onReply(this.props.status, this.props.history); @@ -136,7 +133,7 @@ class StatusActionBar extends ImmutablePureComponent { }; handleFavouriteClick = () => { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { this.props.onFavourite(this.props.status); @@ -146,7 +143,7 @@ class StatusActionBar extends ImmutablePureComponent { }; handleReblogClick = e => { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { this.props.onReblog(this.props.status, e); @@ -250,7 +247,7 @@ class StatusActionBar extends ImmutablePureComponent { render () { const { status, relationship, intl, withDismiss, withCounters, scrollKey } = this.props; - const { signedIn, permissions } = this.context.identity; + const { signedIn, permissions } = this.props.identity; const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility')); @@ -410,4 +407,4 @@ class StatusActionBar extends ImmutablePureComponent { } -export default withRouter(connect(mapStateToProps)(injectIntl(StatusActionBar))); +export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusActionBar)))); diff --git a/app/javascript/mastodon/components/status_content.jsx b/app/javascript/mastodon/components/status_content.jsx index 4a7ba941eb..24483cf512 100644 --- a/app/javascript/mastodon/components/status_content.jsx +++ b/app/javascript/mastodon/components/status_content.jsx @@ -12,8 +12,10 @@ import { connect } from 'react-redux'; import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; import { Icon } from 'mastodon/components/icon'; import PollContainer from 'mastodon/containers/poll_container'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state'; + const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top) /** @@ -67,12 +69,8 @@ const mapStateToProps = state => ({ }); class StatusContent extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, status: ImmutablePropTypes.map.isRequired, statusContent: PropTypes.string, expanded: PropTypes.bool, @@ -245,7 +243,7 @@ class StatusContent extends PureComponent { const renderReadMore = this.props.onClick && status.get('collapsed'); const contentLocale = intl.locale.replace(/[_-].*/, ''); const targetLanguages = this.props.languages?.get(status.get('language') || 'und'); - const renderTranslate = this.props.onTranslate && this.context.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale); + const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale); const content = { __html: statusContent ?? getStatusContent(status) }; const spoilerContent = { __html: status.getIn(['translation', 'spoilerHtml']) || status.get('spoilerHtml') }; @@ -328,4 +326,4 @@ class StatusContent extends PureComponent { } -export default withRouter(connect(mapStateToProps)(injectIntl(StatusContent))); +export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusContent)))); diff --git a/app/javascript/mastodon/containers/mastodon.jsx b/app/javascript/mastodon/containers/mastodon.jsx index 87708da191..0b1255c336 100644 --- a/app/javascript/mastodon/containers/mastodon.jsx +++ b/app/javascript/mastodon/containers/mastodon.jsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import { PureComponent } from 'react'; import { Helmet } from 'react-helmet'; @@ -14,6 +13,7 @@ import { connectUserStream } from 'mastodon/actions/streaming'; import ErrorBoundary from 'mastodon/components/error_boundary'; import { Router } from 'mastodon/components/router'; import UI from 'mastodon/features/ui'; +import { IdentityContext, createIdentityContext } from 'mastodon/identity_context'; import initialState, { title as siteTitle } from 'mastodon/initial_state'; import { IntlProvider } from 'mastodon/locales'; import { store } from 'mastodon/store'; @@ -28,33 +28,9 @@ if (initialState.meta.me) { store.dispatch(fetchCustomEmojis()); } -const createIdentityContext = state => ({ - signedIn: !!state.meta.me, - accountId: state.meta.me, - disabledAccountId: state.meta.disabled_account_id, - accessToken: state.meta.access_token, - permissions: state.role ? state.role.permissions : 0, -}); - export default class Mastodon extends PureComponent { - - static childContextTypes = { - identity: PropTypes.shape({ - signedIn: PropTypes.bool.isRequired, - accountId: PropTypes.string, - disabledAccountId: PropTypes.string, - accessToken: PropTypes.string, - }).isRequired, - }; - identity = createIdentityContext(initialState); - getChildContext() { - return { - identity: this.identity, - }; - } - componentDidMount() { if (this.identity.signedIn) { this.disconnect = store.dispatch(connectUserStream()); @@ -74,19 +50,21 @@ export default class Mastodon extends PureComponent { render () { return ( - - - - - - - - + + + + + + + + + - - - - + + + + + ); } diff --git a/app/javascript/mastodon/features/account/components/header.jsx b/app/javascript/mastodon/features/account/components/header.jsx index e9d6071a21..b10ef6ef76 100644 --- a/app/javascript/mastodon/features/account/components/header.jsx +++ b/app/javascript/mastodon/features/account/components/header.jsx @@ -25,6 +25,7 @@ import { IconButton } from 'mastodon/components/icon_button'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { ShortNumber } from 'mastodon/components/short_number'; import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { autoPlayGif, me, domain as localDomain } from 'mastodon/initial_state'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; @@ -111,6 +112,7 @@ const dateFormatOptions = { class Header extends ImmutablePureComponent { static propTypes = { + identity: identityContextPropShape, account: ImmutablePropTypes.record, identity_props: ImmutablePropTypes.list, onFollow: PropTypes.func.isRequired, @@ -136,10 +138,6 @@ class Header extends ImmutablePureComponent { ...WithRouterPropTypes, }; - static contextTypes = { - identity: PropTypes.object, - }; - setRef = c => { this.node = c; }; @@ -255,7 +253,7 @@ class Header extends ImmutablePureComponent { render () { const { account, hidden, intl } = this.props; - const { signedIn, permissions } = this.context.identity; + const { signedIn, permissions } = this.props.identity; if (!account) { return null; @@ -516,4 +514,4 @@ class Header extends ImmutablePureComponent { } -export default withRouter(injectIntl(Header)); +export default withRouter(withIdentity(injectIntl(Header))); diff --git a/app/javascript/mastodon/features/community_timeline/index.jsx b/app/javascript/mastodon/features/community_timeline/index.jsx index 0aa1f9aa23..5652ea5327 100644 --- a/app/javascript/mastodon/features/community_timeline/index.jsx +++ b/app/javascript/mastodon/features/community_timeline/index.jsx @@ -9,6 +9,7 @@ import { connect } from 'react-redux'; import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; import { DismissableBanner } from 'mastodon/components/dismissable_banner'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { domain } from 'mastodon/initial_state'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; @@ -38,16 +39,12 @@ const mapStateToProps = (state, { columnId }) => { }; class CommunityTimeline extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static defaultProps = { onlyMedia: false, }; static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, columnId: PropTypes.string, intl: PropTypes.object.isRequired, @@ -77,7 +74,7 @@ class CommunityTimeline extends PureComponent { componentDidMount () { const { dispatch, onlyMedia } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; dispatch(expandCommunityTimeline({ onlyMedia })); @@ -87,7 +84,7 @@ class CommunityTimeline extends PureComponent { } componentDidUpdate (prevProps) { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (prevProps.onlyMedia !== this.props.onlyMedia) { const { dispatch, onlyMedia } = this.props; @@ -161,4 +158,4 @@ class CommunityTimeline extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(CommunityTimeline)); +export default withIdentity(connect(mapStateToProps)(injectIntl(CommunityTimeline))); diff --git a/app/javascript/mastodon/features/compose/components/search.jsx b/app/javascript/mastodon/features/compose/components/search.jsx index ca02c23fc4..7fa7ad248b 100644 --- a/app/javascript/mastodon/features/compose/components/search.jsx +++ b/app/javascript/mastodon/features/compose/components/search.jsx @@ -12,6 +12,7 @@ import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import { Icon } from 'mastodon/components/icon'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { domain, searchEnabled } from 'mastodon/initial_state'; import { HASHTAG_REGEX } from 'mastodon/utils/hashtags'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; @@ -33,12 +34,8 @@ const labelForRecentSearch = search => { }; class Search extends PureComponent { - - static contextTypes = { - identity: PropTypes.object.isRequired, - }; - static propTypes = { + identity: identityContextPropShape, value: PropTypes.string.isRequired, recent: ImmutablePropTypes.orderedSet, submitted: PropTypes.bool, @@ -276,7 +273,7 @@ class Search extends PureComponent { } _calculateOptions (value) { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const trimmedValue = value.trim(); const options = []; @@ -318,7 +315,7 @@ class Search extends PureComponent { render () { const { intl, value, submitted, recent } = this.props; const { expanded, options, selectedOption } = this.state; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const hasValue = value.length > 0 || submitted; @@ -402,4 +399,4 @@ class Search extends PureComponent { } -export default withRouter(injectIntl(Search)); +export default withRouter(withIdentity(injectIntl(Search))); diff --git a/app/javascript/mastodon/features/explore/index.jsx b/app/javascript/mastodon/features/explore/index.jsx index d77aec7013..83e5df22f8 100644 --- a/app/javascript/mastodon/features/explore/index.jsx +++ b/app/javascript/mastodon/features/explore/index.jsx @@ -13,6 +13,7 @@ import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; import Search from 'mastodon/features/compose/containers/search_container'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { trendsEnabled } from 'mastodon/initial_state'; import Links from './links'; @@ -32,12 +33,8 @@ const mapStateToProps = state => ({ }); class Explore extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, multiColumn: PropTypes.bool, isSearching: PropTypes.bool, @@ -53,7 +50,7 @@ class Explore extends PureComponent { render() { const { intl, multiColumn, isSearching } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; return ( @@ -114,4 +111,4 @@ class Explore extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(Explore)); +export default withIdentity(connect(mapStateToProps)(injectIntl(Explore))); diff --git a/app/javascript/mastodon/features/firehose/index.jsx b/app/javascript/mastodon/features/firehose/index.jsx index c65fe48eac..f65bee45ec 100644 --- a/app/javascript/mastodon/features/firehose/index.jsx +++ b/app/javascript/mastodon/features/firehose/index.jsx @@ -6,13 +6,14 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; import { Helmet } from 'react-helmet'; import { NavLink } from 'react-router-dom'; +import { useIdentity } from '@/mastodon/identity_context'; import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { addColumn } from 'mastodon/actions/columns'; import { changeSetting } from 'mastodon/actions/settings'; import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming'; import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines'; import { DismissableBanner } from 'mastodon/components/dismissable_banner'; -import initialState, { domain } from 'mastodon/initial_state'; +import { domain } from 'mastodon/initial_state'; import { useAppDispatch, useAppSelector } from 'mastodon/store'; import Column from '../../components/column'; @@ -24,15 +25,6 @@ const messages = defineMessages({ title: { id: 'column.firehose', defaultMessage: 'Live feeds' }, }); -// TODO: use a proper React context later on -const useIdentity = () => ({ - signedIn: !!initialState.meta.me, - accountId: initialState.meta.me, - disabledAccountId: initialState.meta.disabled_account_id, - accessToken: initialState.meta.access_token, - permissions: initialState.role ? initialState.role.permissions : 0, -}); - const ColumnSettings = () => { const dispatch = useAppDispatch(); const settings = useAppSelector((state) => state.getIn(['settings', 'firehose'])); diff --git a/app/javascript/mastodon/features/getting_started/index.jsx b/app/javascript/mastodon/features/getting_started/index.jsx index db6e0f6ecd..628bbe62bb 100644 --- a/app/javascript/mastodon/features/getting_started/index.jsx +++ b/app/javascript/mastodon/features/getting_started/index.jsx @@ -24,6 +24,7 @@ import { fetchFollowRequests } from 'mastodon/actions/accounts'; import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; import LinkFooter from 'mastodon/features/ui/components/link_footer'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { me, showTrends } from '../../initial_state'; import { NavigationBar } from '../compose/components/navigation_bar'; @@ -75,12 +76,8 @@ const badgeDisplay = (number, limit) => { }; class GettingStarted extends ImmutablePureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, myAccount: ImmutablePropTypes.record, multiColumn: PropTypes.bool, @@ -91,7 +88,7 @@ class GettingStarted extends ImmutablePureComponent { componentDidMount () { const { fetchFollowRequests } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (!signedIn) { return; @@ -102,7 +99,7 @@ class GettingStarted extends ImmutablePureComponent { render () { const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const navItems = []; @@ -167,4 +164,4 @@ class GettingStarted extends ImmutablePureComponent { } -export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(GettingStarted)); +export default withIdentity(connect(mapStateToProps, mapDispatchToProps)(injectIntl(GettingStarted))); diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.jsx b/app/javascript/mastodon/features/hashtag_timeline/index.jsx index f431a7e9b7..42a668859e 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.jsx +++ b/app/javascript/mastodon/features/hashtag_timeline/index.jsx @@ -17,6 +17,7 @@ import { fetchHashtag, followHashtag, unfollowHashtag } from 'mastodon/actions/t import { expandHashtagTimeline, clearTimeline } from 'mastodon/actions/timelines'; import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import StatusListContainer from '../ui/containers/status_list_container'; @@ -29,14 +30,10 @@ const mapStateToProps = (state, props) => ({ }); class HashtagTimeline extends PureComponent { - disconnects = []; - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, params: PropTypes.object.isRequired, columnId: PropTypes.string, dispatch: PropTypes.func.isRequired, @@ -94,7 +91,7 @@ class HashtagTimeline extends PureComponent { }; _subscribe (dispatch, id, tags = {}, local) { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (!signedIn) { return; @@ -168,7 +165,7 @@ class HashtagTimeline extends PureComponent { handleFollow = () => { const { dispatch, params, tag } = this.props; const { id } = params; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (!signedIn) { return; @@ -185,7 +182,7 @@ class HashtagTimeline extends PureComponent { const { hasUnread, columnId, multiColumn, tag } = this.props; const { id, local } = this.props.params; const pinned = !!columnId; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; return ( @@ -225,4 +222,4 @@ class HashtagTimeline extends PureComponent { } -export default connect(mapStateToProps)(HashtagTimeline); +export default connect(mapStateToProps)(withIdentity(HashtagTimeline)); diff --git a/app/javascript/mastodon/features/home_timeline/index.jsx b/app/javascript/mastodon/features/home_timeline/index.jsx index 6e7dc2b6c8..00b5835a16 100644 --- a/app/javascript/mastodon/features/home_timeline/index.jsx +++ b/app/javascript/mastodon/features/home_timeline/index.jsx @@ -14,6 +14,7 @@ import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/an import { IconWithBadge } from 'mastodon/components/icon_with_badge'; import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator'; import AnnouncementsContainer from 'mastodon/features/getting_started/containers/announcements_container'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { criticalUpdatesPending } from 'mastodon/initial_state'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; @@ -40,12 +41,8 @@ const mapStateToProps = state => ({ }); class HomeTimeline extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, hasUnread: PropTypes.bool, @@ -126,7 +123,7 @@ class HomeTimeline extends PureComponent { render () { const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props; const pinned = !!columnId; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const banners = []; let announcementsButton; @@ -190,4 +187,4 @@ class HomeTimeline extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(HomeTimeline)); +export default connect(mapStateToProps)(withIdentity(injectIntl(HomeTimeline))); diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.jsx b/app/javascript/mastodon/features/notifications/components/column_settings.jsx index fc737c0fe2..e375b856c9 100644 --- a/app/javascript/mastodon/features/notifications/components/column_settings.jsx +++ b/app/javascript/mastodon/features/notifications/components/column_settings.jsx @@ -5,6 +5,7 @@ import { FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions'; import { CheckboxWithLabel } from './checkbox_with_label'; @@ -12,13 +13,9 @@ import ClearColumnButton from './clear_column_button'; import GrantPermissionButton from './grant_permission_button'; import SettingToggle from './setting_toggle'; -export default class ColumnSettings extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - +class ColumnSettings extends PureComponent { static propTypes = { + identity: identityContextPropShape, settings: ImmutablePropTypes.map.isRequired, pushSettings: ImmutablePropTypes.map.isRequired, onChange: PropTypes.func.isRequired, @@ -215,7 +212,7 @@ export default class ColumnSettings extends PureComponent {

?H( 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 VBYhwK;8h0z;L4iNN=37f{{_(>6$k(T literal 76264 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 JYLu*y{|87bADsXI diff --git a/app/javascript/icons/android-chrome-384x384.png b/app/javascript/icons/android-chrome-384x384.png index add9cb06b9c85fe912c3b51974ed0ee9355b9e19..9d256a83cb3af2ccd3a8ff93cfe4a4bc7528532e 100644 GIT binary patch literal 21112 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 KE0-%;hW-aH@Ujj7 literal 165191 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�X3wc^&m?u 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

- {((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && ( + {((this.props.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && (

@@ -228,7 +225,7 @@ export default class ColumnSettings extends PureComponent {
)} - {((this.context.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && ( + {((this.props.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && (

@@ -245,3 +242,5 @@ export default class ColumnSettings extends PureComponent { } } + +export default withIdentity(ColumnSettings); diff --git a/app/javascript/mastodon/features/notifications/index.jsx b/app/javascript/mastodon/features/notifications/index.jsx index e062957ff8..d45f517152 100644 --- a/app/javascript/mastodon/features/notifications/index.jsx +++ b/app/javascript/mastodon/features/notifications/index.jsx @@ -17,6 +17,7 @@ import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg? import { compareId } from 'mastodon/compare_id'; import { Icon } from 'mastodon/components/icon'; import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { submitMarkers } from '../../actions/markers'; @@ -77,12 +78,8 @@ const mapStateToProps = state => ({ }); class Notifications extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, columnId: PropTypes.string, notifications: ImmutablePropTypes.list.isRequired, dispatch: PropTypes.func.isRequired, @@ -190,7 +187,7 @@ class Notifications extends PureComponent { const { intl, notifications, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props; const pinned = !!columnId; const emptyMessage = ; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; let scrollableContent = null; @@ -299,4 +296,4 @@ class Notifications extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(Notifications)); +export default connect(mapStateToProps)(withIdentity(injectIntl(Notifications))); diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx index 7a163a8825..d6b1b5fa81 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx @@ -18,6 +18,7 @@ import { replyCompose } from 'mastodon/actions/compose'; import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions'; import { openModal } from 'mastodon/actions/modal'; import { IconButton } from 'mastodon/components/icon_button'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { me, boostModal } from 'mastodon/initial_state'; import { makeGetStatus } from 'mastodon/selectors'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; @@ -47,12 +48,8 @@ const makeMapStateToProps = () => { }; class Footer extends ImmutablePureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, statusId: PropTypes.string.isRequired, status: ImmutablePropTypes.map.isRequired, intl: PropTypes.object.isRequired, @@ -75,7 +72,7 @@ class Footer extends ImmutablePureComponent { handleReplyClick = () => { const { dispatch, askReplyConfirmation, status, intl } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (askReplyConfirmation) { @@ -104,7 +101,7 @@ class Footer extends ImmutablePureComponent { handleFavouriteClick = () => { const { dispatch, status } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (status.get('favourited')) { @@ -131,7 +128,7 @@ class Footer extends ImmutablePureComponent { handleReblogClick = e => { const { dispatch, status } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (status.get('reblogged')) { @@ -209,4 +206,4 @@ class Footer extends ImmutablePureComponent { } -export default connect(makeMapStateToProps)(withRouter(injectIntl(Footer))); +export default connect(makeMapStateToProps)(withIdentity(withRouter(injectIntl(Footer)))); diff --git a/app/javascript/mastodon/features/public_timeline/index.jsx b/app/javascript/mastodon/features/public_timeline/index.jsx index 3601dfeae8..91351901f5 100644 --- a/app/javascript/mastodon/features/public_timeline/index.jsx +++ b/app/javascript/mastodon/features/public_timeline/index.jsx @@ -9,6 +9,7 @@ import { connect } from 'react-redux'; import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { DismissableBanner } from 'mastodon/components/dismissable_banner'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { domain } from 'mastodon/initial_state'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; @@ -40,16 +41,12 @@ const mapStateToProps = (state, { columnId }) => { }; class PublicTimeline extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static defaultProps = { onlyMedia: false, }; static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, columnId: PropTypes.string, @@ -80,7 +77,7 @@ class PublicTimeline extends PureComponent { componentDidMount () { const { dispatch, onlyMedia, onlyRemote } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; dispatch(expandPublicTimeline({ onlyMedia, onlyRemote })); @@ -90,7 +87,7 @@ class PublicTimeline extends PureComponent { } componentDidUpdate (prevProps) { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.onlyRemote !== this.props.onlyRemote) { const { dispatch, onlyMedia, onlyRemote } = this.props; @@ -164,4 +161,4 @@ class PublicTimeline extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(PublicTimeline)); +export default connect(mapStateToProps)(withIdentity(injectIntl(PublicTimeline))); diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index 69209e8bd0..d610539987 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -21,6 +21,7 @@ import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react'; import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react'; import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react'; import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; @@ -67,12 +68,8 @@ const mapStateToProps = (state, { status }) => ({ }); class ActionBar extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, status: ImmutablePropTypes.map.isRequired, relationship: ImmutablePropTypes.record, onReply: PropTypes.func.isRequired, @@ -198,7 +195,7 @@ class ActionBar extends PureComponent { render () { const { status, relationship, intl } = this.props; - const { signedIn, permissions } = this.context.identity; + const { signedIn, permissions } = this.props.identity; const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility')); @@ -326,4 +323,4 @@ class ActionBar extends PureComponent { } -export default withRouter(connect(mapStateToProps)(injectIntl(ActionBar))); +export default withRouter(connect(mapStateToProps)(withIdentity(injectIntl(ActionBar)))); diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 3914759725..3a9bf524f8 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -20,6 +20,7 @@ import { Icon } from 'mastodon/components/icon'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import ScrollContainer from 'mastodon/containers/scroll_container'; import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; import { @@ -189,12 +190,8 @@ const titleFromStatus = (intl, status) => { }; class Status extends ImmutablePureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, status: ImmutablePropTypes.map, @@ -244,7 +241,7 @@ class Status extends ImmutablePureComponent { handleFavouriteClick = (status) => { const { dispatch } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (status.get('favourited')) { @@ -274,7 +271,7 @@ class Status extends ImmutablePureComponent { handleReplyClick = (status) => { const { askReplyConfirmation, dispatch, intl } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (askReplyConfirmation) { @@ -307,7 +304,7 @@ class Status extends ImmutablePureComponent { handleReblogClick = (status, e) => { const { dispatch } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (status.get('reblogged')) { @@ -745,4 +742,4 @@ class Status extends ImmutablePureComponent { } -export default withRouter(injectIntl(connect(makeMapStateToProps)(Status))); +export default withRouter(injectIntl(connect(makeMapStateToProps)(withIdentity(Status)))); diff --git a/app/javascript/mastodon/features/ui/components/compose_panel.jsx b/app/javascript/mastodon/features/ui/components/compose_panel.jsx index e6ac79bdd9..18321cbe63 100644 --- a/app/javascript/mastodon/features/ui/components/compose_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/compose_panel.jsx @@ -7,16 +7,13 @@ import { changeComposing, mountCompose, unmountCompose } from 'mastodon/actions/ import ServerBanner from 'mastodon/components/server_banner'; import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container'; import SearchContainer from 'mastodon/features/compose/containers/search_container'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import LinkFooter from './link_footer'; class ComposePanel extends PureComponent { - - static contextTypes = { - identity: PropTypes.object.isRequired, - }; - static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, }; @@ -41,7 +38,7 @@ class ComposePanel extends PureComponent { } render() { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; return (
@@ -65,4 +62,4 @@ class ComposePanel extends PureComponent { } -export default connect()(ComposePanel); +export default connect()(withIdentity(ComposePanel)); diff --git a/app/javascript/mastodon/features/ui/components/header.jsx b/app/javascript/mastodon/features/ui/components/header.jsx index 2f8636b12a..19c76c722b 100644 --- a/app/javascript/mastodon/features/ui/components/header.jsx +++ b/app/javascript/mastodon/features/ui/components/header.jsx @@ -13,6 +13,7 @@ import { fetchServer } from 'mastodon/actions/server'; import { Avatar } from 'mastodon/components/avatar'; import { Icon } from 'mastodon/components/icon'; import { WordmarkLogo, SymbolLogo } from 'mastodon/components/logo'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { registrationsOpen, me, sso_redirect } from 'mastodon/initial_state'; const Account = connect(state => ({ @@ -41,12 +42,8 @@ const mapDispatchToProps = (dispatch) => ({ }); class Header extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, openClosedRegistrationsModal: PropTypes.func, location: PropTypes.object, signupUrl: PropTypes.string.isRequired, @@ -60,7 +57,7 @@ class Header extends PureComponent { } render () { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const { location, openClosedRegistrationsModal, signupUrl, intl } = this.props; let content; @@ -121,4 +118,4 @@ class Header extends PureComponent { } -export default injectIntl(withRouter(connect(mapStateToProps, mapDispatchToProps)(Header))); +export default injectIntl(withRouter(withIdentity(connect(mapStateToProps, mapDispatchToProps)(Header)))); diff --git a/app/javascript/mastodon/features/ui/components/link_footer.jsx b/app/javascript/mastodon/features/ui/components/link_footer.jsx index 6b1555243b..08af6fa444 100644 --- a/app/javascript/mastodon/features/ui/components/link_footer.jsx +++ b/app/javascript/mastodon/features/ui/components/link_footer.jsx @@ -8,6 +8,7 @@ import { Link } from 'react-router-dom'; import { connect } from 'react-redux'; import { openModal } from 'mastodon/actions/modal'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { domain, version, source_url, statusPageUrl, profile_directory as profileDirectory } from 'mastodon/initial_state'; import { PERMISSION_INVITE_USERS } from 'mastodon/permissions'; import { logOut } from 'mastodon/utils/log_out'; @@ -32,12 +33,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }); class LinkFooter extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, multiColumn: PropTypes.bool, onLogout: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, @@ -53,7 +50,7 @@ class LinkFooter extends PureComponent { }; render () { - const { signedIn, permissions } = this.context.identity; + const { signedIn, permissions } = this.props.identity; const { multiColumn } = this.props; const canInvite = signedIn && ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS); @@ -108,4 +105,4 @@ class LinkFooter extends PureComponent { } -export default injectIntl(connect(null, mapDispatchToProps)(LinkFooter)); +export default injectIntl(withIdentity(connect(null, mapDispatchToProps)(LinkFooter))); diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx index 14a1933436..ff90eef359 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx @@ -31,6 +31,7 @@ import { fetchFollowRequests } from 'mastodon/actions/accounts'; import { IconWithBadge } from 'mastodon/components/icon_with_badge'; import { WordmarkLogo } from 'mastodon/components/logo'; import { NavigationPortal } from 'mastodon/components/navigation_portal'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { timelinePreview, trendsEnabled } from 'mastodon/initial_state'; import { transientSingleColumn } from 'mastodon/is_mobile'; @@ -97,12 +98,8 @@ const FollowRequestsLink = () => { }; class NavigationPanel extends Component { - - static contextTypes = { - identity: PropTypes.object.isRequired, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, }; @@ -112,7 +109,7 @@ class NavigationPanel extends Component { render () { const { intl } = this.props; - const { signedIn, disabledAccountId } = this.context.identity; + const { signedIn, disabledAccountId } = this.props.identity; let banner = undefined; @@ -189,4 +186,4 @@ class NavigationPanel extends Component { } -export default injectIntl(NavigationPanel); +export default injectIntl(withIdentity(NavigationPanel)); diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index c84a2c51a4..7742f64860 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -15,6 +15,7 @@ import { focusApp, unfocusApp, changeLayout } from 'mastodon/actions/app'; import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers'; import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding'; import { PictureInPicture } from 'mastodon/features/picture_in_picture'; +import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { layoutFromWindow } from 'mastodon/is_mobile'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; @@ -120,12 +121,8 @@ const keyMap = { }; class SwitchingColumnsArea extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, children: PropTypes.node, location: PropTypes.object, singleColumn: PropTypes.bool, @@ -160,7 +157,7 @@ class SwitchingColumnsArea extends PureComponent { render () { const { children, singleColumn } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const pathName = this.props.location.pathname; let redirect; @@ -252,12 +249,8 @@ class SwitchingColumnsArea extends PureComponent { } class UI extends PureComponent { - - static contextTypes = { - identity: PropTypes.object.isRequired, - }; - static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, children: PropTypes.node, isComposing: PropTypes.bool, @@ -309,7 +302,7 @@ class UI extends PureComponent { this.dragTargets.push(e.target); } - if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore && this.context.identity.signedIn) { + if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore && this.props.identity.signedIn) { this.setState({ draggingOver: true }); } }; @@ -337,7 +330,7 @@ class UI extends PureComponent { this.setState({ draggingOver: false }); this.dragTargets = []; - if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore && this.context.identity.signedIn) { + if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore && this.props.identity.signedIn) { this.props.dispatch(uploadCompose(e.dataTransfer.files)); } }; @@ -389,7 +382,7 @@ class UI extends PureComponent { }; componentDidMount () { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; window.addEventListener('focus', this.handleWindowFocus, false); window.addEventListener('blur', this.handleWindowBlur, false); @@ -586,7 +579,7 @@ class UI extends PureComponent {
- + {children} @@ -602,4 +595,4 @@ class UI extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(withRouter(UI))); +export default connect(mapStateToProps)(injectIntl(withRouter(withIdentity(UI)))); diff --git a/app/javascript/mastodon/identity_context.tsx b/app/javascript/mastodon/identity_context.tsx new file mode 100644 index 0000000000..564b7895c9 --- /dev/null +++ b/app/javascript/mastodon/identity_context.tsx @@ -0,0 +1,74 @@ +import PropTypes from 'prop-types'; +import { createContext, useContext } from 'react'; + +import hoistStatics from 'hoist-non-react-statics'; + +import type { InitialState } from 'mastodon/initial_state'; + +export interface IdentityContextType { + signedIn: boolean; + accountId: string | undefined; + disabledAccountId: string | undefined; + accessToken: string | undefined; + permissions: number; +} + +export const identityContextPropShape = PropTypes.shape({ + signedIn: PropTypes.bool.isRequired, + accountId: PropTypes.string, + disabledAccountId: PropTypes.string, + accessToken: PropTypes.string, +}).isRequired; + +export const createIdentityContext = (state: InitialState) => ({ + signedIn: !!state.meta.me, + accountId: state.meta.me, + disabledAccountId: state.meta.disabled_account_id, + accessToken: state.meta.access_token, + permissions: state.role?.permissions ?? 0, +}); + +export const IdentityContext = createContext({ + signedIn: false, + permissions: 0, + accountId: undefined, + disabledAccountId: undefined, + accessToken: undefined, +}); + +export const useIdentity = () => useContext(IdentityContext); + +export interface IdentityProps { + ref?: unknown; + wrappedComponentRef?: unknown; +} + +/* Injects an `identity` props into the wrapped component to be able to use the new context in class components */ +export function withIdentity< + ComponentType extends React.ComponentType, +>(Component: ComponentType) { + const displayName = `withIdentity(${Component.displayName ?? Component.name})`; + const C = (props: React.ComponentProps) => { + const { wrappedComponentRef, ...remainingProps } = props; + + return ( + + {(context) => { + return ( + // @ts-expect-error - Dynamic covariant generic components are tough to type. + + ); + }} + + ); + }; + + C.displayName = displayName; + C.WrappedComponent = Component; + + return hoistStatics(C, Component); +} diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index d8c57a2a0c..5d60565e17 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -44,12 +44,22 @@ * @property {string} sso_redirect */ +/** + * @typedef Role + * @property {string} id + * @property {string} name + * @property {string} permissions + * @property {string} color + * @property {boolean} highlighted + */ + /** * @typedef InitialState * @property {Record} accounts * @property {InitialStateLanguage[]} languages * @property {boolean=} critical_updates_pending * @property {InitialStateMeta} meta + * @property {Role?} role */ const element = document.getElementById('initial-state'); From 0a343b9a91bc11fd61090fea027431d1e6b94479 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 19:15:06 +0200 Subject: [PATCH 193/658] fix(deps): update react monorepo to v18.3.1 (#30074) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index efe8cc0264..0fd8ead3a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14269,14 +14269,14 @@ __metadata: linkType: hard "react-dom@npm:^18.2.0": - version: 18.2.0 - resolution: "react-dom@npm:18.2.0" + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" dependencies: loose-envify: "npm:^1.1.0" - scheduler: "npm:^0.23.0" + scheduler: "npm:^0.23.2" peerDependencies: - react: ^18.2.0 - checksum: 10c0/66dfc5f93e13d0674e78ef41f92ed21dfb80f9c4ac4ac25a4b51046d41d4d2186abc915b897f69d3d0ebbffe6184e7c5876f2af26bfa956f179225d921be713a + react: ^18.3.1 + checksum: 10c0/a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85 languageName: node linkType: hard @@ -14679,11 +14679,11 @@ __metadata: linkType: hard "react@npm:^18.2.0": - version: 18.2.0 - resolution: "react@npm:18.2.0" + version: 18.3.1 + resolution: "react@npm:18.3.1" dependencies: loose-envify: "npm:^1.1.0" - checksum: 10c0/b562d9b569b0cb315e44b48099f7712283d93df36b19a39a67c254c6686479d3980b7f013dc931f4a5a3ae7645eae6386b4aa5eea933baa54ecd0f9acb0902b8 + checksum: 10c0/283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3 languageName: node linkType: hard From 0f07e1cd4cf04049eda34d4dfd98c12fafc5e344 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Sun, 19 May 2024 15:37:49 -0400 Subject: [PATCH 194/658] Fix yarn.lock diff (#30366) --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 0fd8ead3a7..4d6fe4d1fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15344,7 +15344,7 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.23.0, scheduler@npm:^0.23.2": +"scheduler@npm:^0.23.2": version: 0.23.2 resolution: "scheduler@npm:0.23.2" dependencies: From 990a0c19a9205fdd8b3e6c0082cc8b80725de144 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 20 May 2024 09:29:27 +0200 Subject: [PATCH 195/658] Fix a warning when running JS Tests because of FakeIdentityContext using deprecated context API (#30368) --- app/javascript/mastodon/test_helpers.tsx | 43 ++++++------------------ 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/app/javascript/mastodon/test_helpers.tsx b/app/javascript/mastodon/test_helpers.tsx index 69d57b95a0..bfea3f6bf4 100644 --- a/app/javascript/mastodon/test_helpers.tsx +++ b/app/javascript/mastodon/test_helpers.tsx @@ -1,7 +1,3 @@ -import PropTypes from 'prop-types'; -import type { PropsWithChildren } from 'react'; -import { Component } from 'react'; - import { IntlProvider } from 'react-intl'; import { MemoryRouter } from 'react-router'; @@ -9,44 +5,27 @@ import { MemoryRouter } from 'react-router'; // eslint-disable-next-line import/no-extraneous-dependencies import { render as rtlRender } from '@testing-library/react'; -class FakeIdentityWrapper extends Component< - PropsWithChildren<{ signedIn: boolean }> -> { - static childContextTypes = { - identity: PropTypes.shape({ - signedIn: PropTypes.bool.isRequired, - accountId: PropTypes.string, - disabledAccountId: PropTypes.string, - accessToken: PropTypes.string, - }).isRequired, - }; - - getChildContext() { - return { - identity: { - signedIn: this.props.signedIn, - accountId: '123', - accessToken: 'test-access-token', - }, - }; - } - - render() { - return this.props.children; - } -} +import { IdentityContext } from './identity_context'; function render( ui: React.ReactElement, { locale = 'en', signedIn = true, ...renderOptions } = {}, ) { + const fakeIdentity = { + signedIn: signedIn, + accountId: '123', + accessToken: 'test-access-token', + disabledAccountId: undefined, + permissions: 0, + }; + const Wrapper = (props: { children: React.ReactNode }) => { return ( - + {props.children} - + ); From 778bd96a52a6c608f78b07f80764046a2eac61b3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 09:40:20 +0200 Subject: [PATCH 196/658] chore(deps): update dependency @types/lodash to v4.17.4 (#30371) 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 4d6fe4d1fa..98b2da3112 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3705,9 +3705,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.195": - version: 4.17.1 - resolution: "@types/lodash@npm:4.17.1" - checksum: 10c0/af2ad8a3c8d7deb170a7ec6e18afc5ae8980576e5f7fe798d8a95a1df7222c15bdf967a25a35879f575a3b64743de00145710ee461a0051e055e94e4fe253f45 + version: 4.17.4 + resolution: "@types/lodash@npm:4.17.4" + checksum: 10c0/0124c64cb9fe7a0f78b6777955abd05ef0d97844d49118652eae45f8fa57bfb7f5a7a9bccc0b5a84c0a6dc09631042e4590cb665acb9d58dfd5e6543c75341ec languageName: node linkType: hard From 814d00cf4b8942b87db17b2bc2877f25d7e83f96 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 09:40:37 +0200 Subject: [PATCH 197/658] chore(deps): update dependency @formatjs/cli to v6.2.12 (#30370) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 98b2da3112..6b1dd8d22d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2215,13 +2215,13 @@ __metadata: linkType: hard "@formatjs/cli@npm:^6.1.1": - version: 6.2.10 - resolution: "@formatjs/cli@npm:6.2.10" + version: 6.2.12 + resolution: "@formatjs/cli@npm:6.2.12" peerDependencies: "@glimmer/env": ^0.1.7 - "@glimmer/reference": ^0.91.1 - "@glimmer/syntax": ^0.91.1 - "@glimmer/validator": ^0.91.1 + "@glimmer/reference": ^0.91.1 || ^0.92.0 + "@glimmer/syntax": ^0.92.0 + "@glimmer/validator": ^0.92.0 "@vue/compiler-core": ^3.4.0 content-tag: ^2.0.1 ember-template-recast: ^6.1.4 @@ -2245,7 +2245,7 @@ __metadata: optional: true bin: formatjs: bin/formatjs - checksum: 10c0/34b1b0b3be25d945111c1f57913f50da7308ecd05501a27eaca210a774eb50c616b5706ba796d37ffa223ac4c5cddd5f36fe0ca8d31ad8c8ade79cdd497ccfb9 + checksum: 10c0/3bd05a9fad6c837e22988e6638f426c128efa46ab80ff88cf2ad81fb3bc10cf4f228907577fc01e24c2d7d505cfabfaa69f0496d2ec8f0ab2d6b5eaccb5e475c languageName: node linkType: hard From 8b75d18371edb1830de72b83737f94d9024b32b4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 09:41:38 +0200 Subject: [PATCH 198/658] New Crowdin Translations (automated) (#30358) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ia.json | 30 +-- app/javascript/mastodon/locales/ru.json | 1 + app/javascript/mastodon/locales/sl.json | 1 + app/javascript/mastodon/locales/th.json | 2 +- config/locales/bg.yml | 1 + config/locales/ca.yml | 1 + config/locales/da.yml | 1 + config/locales/de.yml | 1 + config/locales/devise.ia.yml | 53 +++-- config/locales/doorkeeper.ia.yml | 77 +++++- config/locales/es-AR.yml | 1 + config/locales/es-MX.yml | 1 + config/locales/es.yml | 1 + config/locales/fi.yml | 1 + config/locales/fo.yml | 1 + config/locales/gl.yml | 1 + config/locales/he.yml | 1 + config/locales/hu.yml | 1 + config/locales/ia.yml | 301 ++++++++++++++++++++++++ config/locales/it.yml | 1 + config/locales/ko.yml | 1 + config/locales/lad.yml | 1 + config/locales/nl.yml | 1 + config/locales/pl.yml | 1 + config/locales/pt-PT.yml | 1 + config/locales/simple_form.fi.yml | 6 +- config/locales/simple_form.sl.yml | 6 + config/locales/sl.yml | 1 + config/locales/sr-Latn.yml | 1 + config/locales/sr.yml | 1 + config/locales/sv.yml | 1 + config/locales/th.yml | 2 + config/locales/tr.yml | 1 + config/locales/vi.yml | 1 + config/locales/zh-CN.yml | 1 + config/locales/zh-TW.yml | 1 + 36 files changed, 464 insertions(+), 41 deletions(-) diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 313563bdfe..47c64e3f0d 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -19,7 +19,7 @@ "account.block_domain": "Blocar dominio {domain}", "account.block_short": "Blocar", "account.blocked": "Blocate", - "account.browse_more_on_origin_server": "Navigar plus sur le profilo original", + "account.browse_more_on_origin_server": "Percurrer plus sur le profilo original", "account.cancel_follow_request": "Cancellar sequimento", "account.copy": "Copiar ligamine a profilo", "account.direct": "Mentionar privatemente @{name}", @@ -122,7 +122,7 @@ "column.direct": "Mentiones private", "column.directory": "Navigar profilos", "column.domain_blocks": "Dominios blocate", - "column.favourites": "Favoritos", + "column.favourites": "Favorites", "column.firehose": "Fluxos in directo", "column.follow_requests": "Requestas de sequimento", "column.home": "Initio", @@ -204,7 +204,7 @@ "disabled_account_banner.account_settings": "Parametros de conto", "disabled_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate.", "dismissable_banner.community_timeline": "Ecce le messages public le plus recente del personas con contos sur {domain}.", - "dismissable_banner.dismiss": "Dimitter", + "dismissable_banner.dismiss": "Clauder", "dismissable_banner.explore_links": "Istes es le articulos de novas que se condivide le plus sur le rete social hodie. Le articulos de novas le plus recente, publicate per plus personas differente, se classifica plus in alto.", "dismissable_banner.explore_statuses": "Ecce le messages de tote le rete social que gania popularitate hodie. Le messages plus nove con plus impulsos e favorites se classifica plus in alto.", "dismissable_banner.explore_tags": "Ecce le hashtags que gania popularitate sur le rete social hodie. Le hashtags usate per plus personas differente se classifica plus in alto.", @@ -212,8 +212,8 @@ "domain_block_modal.block": "Blocar le servitor", "domain_block_modal.block_account_instead": "Blocar @{name} in su loco", "domain_block_modal.they_can_interact_with_old_posts": "Le personas de iste servitor pote interager con tu messages ancian.", - "domain_block_modal.they_cant_follow": "Nulle persona ab iste servitor pote sequer te.", - "domain_block_modal.they_wont_know": "Illes non sapera que illes ha essite blocate.", + "domain_block_modal.they_cant_follow": "Necuno de iste servitor pote sequer te.", + "domain_block_modal.they_wont_know": "Ille non sapera que ille ha essite blocate.", "domain_block_modal.title": "Blocar dominio?", "domain_block_modal.you_will_lose_followers": "Omne sequitores ab iste servitor essera removite.", "domain_block_modal.you_wont_see_posts": "Tu non videra messages e notificationes ab usatores sur iste servitor.", @@ -307,7 +307,7 @@ "follow_request.reject": "Rejectar", "follow_requests.unlocked_explanation": "Benque tu conto non es serrate, le personal de {domain} pensa que es un bon idea que tu revide manualmente le sequente requestas de iste contos.", "follow_suggestions.curated_suggestion": "Selection del equipa", - "follow_suggestions.dismiss": "Non monstrar novemente", + "follow_suggestions.dismiss": "Non monstrar de novo", "follow_suggestions.featured_longer": "Seligite con cura per le equipa de {domain}", "follow_suggestions.friends_of_friends_longer": "Popular inter le gente que tu seque", "follow_suggestions.hints.featured": "Iste profilo ha essite seligite manualmente per le equipa de {domain}.", @@ -412,7 +412,7 @@ "lightbox.next": "Sequente", "lightbox.previous": "Precedente", "limited_account_hint.action": "Monstrar profilo in omne caso", - "limited_account_hint.title": "Iste profilo esseva celate per le moderatores de {domain}.", + "limited_account_hint.title": "Iste profilo ha essite celate per le moderatores de {domain}.", "link_preview.author": "Per {name}", "lists.account.add": "Adder al lista", "lists.account.remove": "Remover del lista", @@ -432,12 +432,12 @@ "loading_indicator.label": "Cargante…", "media_gallery.toggle_visible": "{number, plural, one {Celar imagine} other {Celar imagines}}", "moved_to_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate perque tu ha cambiate de conto a {movedToAccount}.", - "mute_modal.hide_from_notifications": "Celar ab notificationes", + "mute_modal.hide_from_notifications": "Celar in notificationes", "mute_modal.hide_options": "Celar optiones", "mute_modal.indefinite": "Usque io dissilentia iste persona", "mute_modal.show_options": "Monstrar optiones", - "mute_modal.they_can_mention_and_follow": "Illes pote mentionar te e sequer te, ma tu non potera vider los.", - "mute_modal.they_wont_know": "Illes non sapera que illes ha essite silentiate.", + "mute_modal.they_can_mention_and_follow": "Ille pote mentionar te e sequer te, ma tu non potera vider le.", + "mute_modal.they_wont_know": "Ille non sapera que ille ha essite silentiate.", "mute_modal.title": "Silentiar le usator?", "mute_modal.you_wont_see_mentions": "Tu non videra le messages que mentiona iste persona.", "mute_modal.you_wont_see_posts": "Iste persona pote totevia vider tu messages, ma tu non videra le sues.", @@ -451,13 +451,13 @@ "navigation_bar.discover": "Discoperir", "navigation_bar.domain_blocks": "Dominios blocate", "navigation_bar.explore": "Explorar", - "navigation_bar.favourites": "Favoritos", + "navigation_bar.favourites": "Favorites", "navigation_bar.filters": "Parolas silentiate", "navigation_bar.follow_requests": "Requestas de sequimento", "navigation_bar.followed_tags": "Hashtags sequite", "navigation_bar.follows_and_followers": "Sequites e sequitores", "navigation_bar.lists": "Listas", - "navigation_bar.logout": "Clauder le session", + "navigation_bar.logout": "Clauder session", "navigation_bar.mutes": "Usatores silentiate", "navigation_bar.opened_in_classic_interface": "Messages, contos e altere paginas specific es aperite per predefinition in le interfacie web classic.", "navigation_bar.personal": "Personal", @@ -501,7 +501,7 @@ "notifications.column_settings.admin.report": "Nove signalationes:", "notifications.column_settings.admin.sign_up": "Nove inscriptiones:", "notifications.column_settings.alert": "Notificationes de scriptorio", - "notifications.column_settings.favourite": "Favoritos:", + "notifications.column_settings.favourite": "Favorites:", "notifications.column_settings.filter_bar.advanced": "Monstrar tote le categorias", "notifications.column_settings.filter_bar.category": "Barra de filtro rapide", "notifications.column_settings.follow": "Nove sequitores:", @@ -518,7 +518,7 @@ "notifications.column_settings.update": "Modificationes:", "notifications.filter.all": "Toto", "notifications.filter.boosts": "Impulsos", - "notifications.filter.favourites": "Favoritos", + "notifications.filter.favourites": "Favorites", "notifications.filter.follows": "Sequites", "notifications.filter.mentions": "Mentiones", "notifications.filter.polls": "Resultatos del sondage", @@ -717,7 +717,7 @@ "status.edited": "Ultime modification le {date}", "status.edited_x_times": "Modificate {count, plural, one {{count} vice} other {{count} vices}}", "status.embed": "Incastrar", - "status.favourite": "Adder al favoritos", + "status.favourite": "Adder al favorites", "status.favourites": "{count, plural, one {favorite} other {favorites}}", "status.filter": "Filtrar iste message", "status.filtered": "Filtrate", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index cd09a505b3..07a41385a2 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -468,6 +468,7 @@ "notification.follow": "{name} подписался (-лась) на вас", "notification.follow_request": "{name} отправил запрос на подписку", "notification.mention": "{name} упомянул(а) вас", + "notification.moderation_warning.action_delete_statuses": "Некоторые из ваших публикаций были удалены.", "notification.own_poll": "Ваш опрос закончился", "notification.poll": "Опрос, в котором вы приняли участие, завершился", "notification.reblog": "{name} продвинул(а) ваш пост", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 459d05ce3e..7806abc6b5 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -474,6 +474,7 @@ "notification.follow_request": "{name} vam želi slediti", "notification.mention": "{name} vas je omenil/a", "notification.moderation-warning.learn_more": "Več o tem", + "notification.moderation_warning": "Prejeli ste opozorilo moderatorjev", "notification.moderation_warning.action_delete_statuses": "Nekatere vaše objave so odstranjene.", "notification.moderation_warning.action_disable": "Vaš račun je bil onemogočen.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Nekatere vaše objave so bile označene kot občutljive.", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 7c6b2ade4e..b1b9407ba1 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -158,7 +158,7 @@ "compose_form.poll.option_placeholder": "ตัวเลือก {number}", "compose_form.poll.single": "เลือกอย่างใดอย่างหนึ่ง", "compose_form.poll.switch_to_multiple": "เปลี่ยนการสำรวจความคิดเห็นเป็นอนุญาตหลายตัวเลือก", - "compose_form.poll.switch_to_single": "เปลี่ยนการสำรวจความคิดเห็นเป็นอนุญาตตัวเลือกเดี่ยว", + "compose_form.poll.switch_to_single": "เปลี่ยนการสำรวจความคิดเห็นเป็นอนุญาตตัวเลือกเดียว", "compose_form.poll.type": "ลักษณะ", "compose_form.publish": "โพสต์", "compose_form.publish_form": "โพสต์ใหม่", diff --git a/config/locales/bg.yml b/config/locales/bg.yml index f242039ed8..51180bc66f 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -285,6 +285,7 @@ bg: update_custom_emoji_html: "%{name} обнови емоджито %{target}" update_domain_block_html: "%{name} обнови блокирането на домейна за %{target}" update_ip_block_html: "%{name} промени правило за IP на %{target}" + update_report_html: "%{name} осъвремени доклад %{target}" update_status_html: "%{name} обнови публикация от %{target}" update_user_role_html: "%{name} промени ролята %{target}" deleted_account: изтрит акаунт diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 08fef73642..34fd900851 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -285,6 +285,7 @@ ca: update_custom_emoji_html: "%{name} ha actualitzat l'emoji %{target}" update_domain_block_html: "%{name} ha actualitzat el bloqueig de domini per a %{target}" update_ip_block_html: "%{name} ha canviat la norma per la IP %{target}" + update_report_html: "%{name} ha actualitzat l'informe %{target}" update_status_html: "%{name} ha actualitzat l'estat de %{target}" update_user_role_html: "%{name} ha canviat el rol %{target}" deleted_account: compte eliminat diff --git a/config/locales/da.yml b/config/locales/da.yml index 252d0e2b58..17d3037a75 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -285,6 +285,7 @@ da: update_custom_emoji_html: "%{name} opdaterede emoji %{target}" update_domain_block_html: "%{name} opdaterede domæneblokeringen for %{target}" update_ip_block_html: "%{name} ændrede reglen for IP'en %{target}" + update_report_html: "%{name} opdaterede rapporten %{target}" update_status_html: "%{name} opdaterede indlægget fra %{target}" update_user_role_html: "%{name} ændrede %{target}-rolle" deleted_account: slettet konto diff --git a/config/locales/de.yml b/config/locales/de.yml index b19315e394..dd2129584f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -285,6 +285,7 @@ de: update_custom_emoji_html: "%{name} bearbeitete das Emoji %{target}" update_domain_block_html: "%{name} aktualisierte die Domain-Sperre für %{target}" update_ip_block_html: "%{name} änderte die Regel für die IP-Adresse %{target}" + update_report_html: "%{name} überarbeitete die Meldung %{target}" update_status_html: "%{name} überarbeitete einen Beitrag von %{target}" update_user_role_html: "%{name} änderte die Rolle von %{target}" deleted_account: gelöschtes Konto diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index c68efddd07..e6ae6d4afb 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -6,11 +6,11 @@ ia: send_instructions: Tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe. send_paranoid_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe. failure: - already_authenticated: Tu jam initiava le session. - inactive: Tu conto ancora non es activate. + already_authenticated: Tu ha jam aperite session. + inactive: Tu conto non es ancora activate. invalid: "%{authentication_keys} o contrasigno non valide." last_attempt: Tu ha solmente un altere tentativa ante que tu conto es serrate. - locked: Tu conto es blocate. + locked: Tu conto es serrate. not_found_in_database: "%{authentication_keys} o contrasigno non valide." omniauth_user_creation_failure: Error creante un conto pro iste identitate. pending: Tu conto es ancora sub revision. @@ -51,12 +51,12 @@ ia: explanation: Ora es possibile aperir session con solmente le adresse de e-mail e contrasigno. subject: 'Mastodon: Authentication bifactorial disactivate' subtitle: Le authentication bifactorial ha essite disactivate pro tu conto. - title: 2FA disactivate + title: A2F disactivate two_factor_enabled: explanation: Pro le apertura de session essera necessari un token generate per le application TOTP accopulate. subject: 'Mastodon: Authentication bifactorial activate' subtitle: Le authentication bifactorial ha essite activate pro tu conto. - title: 2FA activate + title: A2F activate two_factor_recovery_codes_changed: explanation: Le ancian codices de recuperation ha essite invalidate e nove codices ha essite generate. subject: 'Mastodon: Codices de recuperation regenerate' @@ -66,11 +66,11 @@ ia: subject: 'Mastodon: Instructiones pro disblocar' webauthn_credential: added: - explanation: Le sequente clave de securitate esseva addite a tu conto + explanation: Le sequente clave de securitate ha essite addite a tu conto subject: 'Mastodon: Nove clave de securitate' - title: Un nove clave de securitate esseva addite + title: Un nove clave de securitate ha essite addite deleted: - explanation: Le sequente clave de securitate esseva delite de tu conto + explanation: Le sequente clave de securitate ha essite delite de tu conto subject: 'Mastodon: Clave de securitate delite' title: Un de tu claves de securitate ha essite delite webauthn_disabled: @@ -81,18 +81,41 @@ ia: webauthn_enabled: explanation: Le authentication con claves de securitate ha essite activate pro tu conto. extra: Tu clave de securitate pote ora esser usate pro aperir session. + subject: 'Mastodon: authentication de clave de securitate activate' title: Claves de securitate activate + omniauth_callbacks: + failure: Impossibile authenticar te ab %{kind} perque “%{reason}”. + success: Authenticate con successo ab conto %{kind}. + passwords: + no_token: Tu non pote acceder iste pagina sin venir ab un email de redefinition de contrasigno. Si tu veni ab un email de redefinition de contrasigno, verifica que tu usava le integre URL fornite. + send_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un ligamine de recuperation de contrasigno in tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe. + send_paranoid_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un ligamine de recuperation de contrasigno in tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe. + updated: Tu contrasigno ha essite cambiate. Tu ha ora aperite session. + updated_not_active: Tu contrasigno ha essite cambiate. 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. + destroyed: A revider! Tu conto ha essite cancellate. Nos spera vider te de novo tosto. + signed_up: Benvenite! Tu te ha inscribite con successo. + signed_up_but_inactive: Tu te ha inscribite con successo. Nonobstante, nos non poteva aperir tu session perque tu conto non es ancora activate. + signed_up_but_locked: Tu te ha inscribite con successo. Nonobstante, nos non poteva aperir tu session perque tu conto es serrate. + signed_up_but_pending: Un message con un ligamine de confirmation ha essite inviate a tu adresse de email. Post que tu clicca sur le ligamine, nos revidera tu demanda. Tu essera notificate si illo es approbate. + signed_up_but_unconfirmed: Un message con un ligamine de confirmation ha essite inviate a tu adresse de e-mail. Per favor seque le ligamine pro activar tu conto. Verifica tu dossier de spam si tu non recipe iste e-mail. + update_needs_confirmation: Tu ha actualisate tu conto con successo, ma nos debe verificar tu nove adresse de e-mail. Accede a tu e-mail e seque le ligamine de confirmation pro confirmar tu nove adresse de e-mail. Verifica tu dossier de spam si tu non recipe iste e-mail. updated: Tu conto ha essite actualisate con successo. sessions: - signed_in: Connexe con successo. - signed_out: Disconnexe con successo. + already_signed_out: Session claudite con successo. + signed_in: Session aperite con successo. + signed_out: Session claudite con successo. unlocks: - unlocked: Tu conto ha essite disblocate con successo. Initia session a continuar. + send_instructions: Tu recipera un e-mail con instructiones explicante como disserrar tu conto in alcun minutas. Verifica tu dossier de spam si tu non recipe iste e-mail. + send_paranoid_instructions: Si tu conto existe, tu recipera un email con instructiones explicante como disserrar lo in alcun minutas. Verifica tu dossier de spam si tu non recipe iste e-mail. + unlocked: Tu conto ha essite disserrate con successo. Aperi session pro continuar. errors: messages: - already_confirmed: jam esseva confirmate, tenta initiar session + already_confirmed: jam esseva confirmate, tenta aperir session + confirmation_period_expired: debe esser confirmate in %{period}, per favor requesta un nove + expired: ha expirate, per favor requesta un nove not_found: non trovate - not_locked: non era blocate + not_locked: non esseva serrate + not_saved: + one: '1 error ha impedite a iste %{resource} de esser salvate:' + other: "%{count} errores ha impedite a iste %{resource} de esser salvate:" diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index dc96599681..9c493e3d7f 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -3,28 +3,40 @@ ia: activerecord: attributes: doorkeeper/application: - name: Nomine de application + name: Nomine del application + redirect_uri: URI de redirection scopes: Ambitos - website: Sito web de application + website: Sito web del application errors: models: doorkeeper/application: attributes: redirect_uri: + fragment_present: non pote continer un fragmento. invalid_uri: debe esser un URI valide. + relative_uri: debe esser un URI absolute. + secured_uri: debe esser un URI HTTPS/SSL. doorkeeper: applications: buttons: authorize: Autorisar cancel: Cancellar + destroy: Destruer edit: Modificar submit: Submitter confirmations: destroy: Es tu secur? edit: title: Modificar application + form: + error: Oops! Verifica tu formulario pro possibile errores + help: + native_redirect_uri: Usar %{native_redirect_uri} pro tests local + redirect_uri: Usar un linea per URI + scopes: Separa ambitos con spatios. Lassa vacue pro usar le ambitos predefinite. index: application: Application + callback_url: URL de retorno delete: Deler empty: Tu non ha applicationes. name: Nomine @@ -37,17 +49,22 @@ ia: show: actions: Actiones application_id: Clave del cliente + callback_urls: URLs de retorno scopes: Ambitos + secret: Secreto del application title: 'Application: %{name}' authorizations: buttons: authorize: Autorisar deny: Negar error: - title: Ocurreva un error + title: Un error ha occurrite new: + prompt_html: "%{client_name} vole haber le permission de acceder a tu conto. Illo es un application tertie. Si tu non confide in illo, alora tu non deberea autorisar lo." review_permissions: Revisionar le permissos title: Autorisation necessari + show: + title: Copia iste codice de autorisation e colla lo in le application. authorized_applications: buttons: revoke: Revocar @@ -55,11 +72,35 @@ ia: revoke: Es tu secur? index: authorized_at: Autorisate le %{date} + description_html: Ecce applicationes que pote acceder tu conto per le API. Si il ha applicationes que tu non recognosce ci, o un application que se comporta mal, tu pote revocar su accesso. last_used_at: Ultime uso in %{date} never_used: Nunquam usate scopes: Permissiones superapp: Interne title: Tu applicationes autorisate + errors: + messages: + access_denied: Le proprietario del ressource o servitor de autorisation ha refusate le requesta. + credential_flow_not_configured: Le processo de credentiales de contrasigno del proprietario del ressource ha fallite perque Doorkeeper.configure.resource_owner_from_credentials non es configurate. + invalid_client: Le authentication del cliente ha fallite perque le cliente es incognite, necun authentication de cliente es includite, o le methodo de authentication non es supportate. + invalid_grant: Le concession de autorisation fornite es invalide, expirate, revocate, non corresponde al URI de redirection usate in le requesta de autorisation, o ha essite emittite a un altere cliente. + invalid_redirect_uri: Le URI de redirection includite non es valide. + invalid_request: + missing_param: 'Parametro requirite mancante: %{value}.' + request_not_authorized: Le requesta debe esser autorisate. Un parametro requirite pro autorisar le requesta manca o non es valide. + unknown: Le requesta non include un parametro requirite, include un valor de parametro non supportate, o es alteremente mal formate. + invalid_resource_owner: Le credentiales del proprietario del ressource fornite non es valide, o le proprietario del ressource non pote esser trovate + invalid_scope: Le ambito requirite es invalide, incognite, o mal formate. + invalid_token: + expired: Le token de accesso ha expirate + revoked: Le token de accesso ha essite revocate + unknown: Le token de accesso non es valide + resource_owner_authenticator_not_configured: Impossibile trovar le proprietario del ressource perque Doorkeeper.configure.resource_owner_authenticator non es configurate. + server_error: Le servitor de autorisation ha incontrate un condition impreviste que lo ha impedite de complir le requesta. + temporarily_unavailable: Le servitor de autorisation actualmente non pote gerer le requesta a causa de un supercarga temporari o de mantenentia del servitor. + unauthorized_client: Le application non es autorisate a exequer iste requesta usante iste methodo. + unsupported_grant_type: Le typo de concession de autorisation non es supportate per le servitor de autorisation. + unsupported_response_type: Le servitor de autorisation non supporta iste typo de responsa. flash: applications: create: @@ -73,20 +114,22 @@ ia: notice: Application revocate. grouped_scopes: access: - read: Accesso de sol lectura + read: Accesso de lectura sol read/write: Accesso de lectura e scriptura - write: Accesso de sol scriptura + write: Accesso de scriptura sol title: accounts: Contos admin/accounts: Gestion de contos admin/all: Tote le functiones administrative admin/reports: Gestion de reportos - all: Accesso plen a tu conto de Mastodon + all: Accesso complete a tu conto de Mastodon blocks: Blocadas bookmarks: Marcapaginas conversations: Conversationes - favourites: Favoritos + crypto: Cryptation de puncta a puncta + favourites: Favorites filters: Filtros + follow: Sequites, silentiates e blocates follows: Sequites lists: Listas media: Annexos multimedial @@ -101,21 +144,41 @@ ia: nav: applications: Applicationes oauth2_provider: Fornitor OAuth2 + application: + title: Autorisation OAuth necessari scopes: admin:read: leger tote le datos in le servitor admin:read:accounts: leger information sensibile de tote le contos + admin:read:canonical_email_blocks: leger datos sensibile de tote le blocadas de email canonic + admin:read:domain_allows: leger informationes sensibile de tote le dominios permittite + admin:read:domain_blocks: leger informationes sensibile de tote le blocadas de dominio + admin:read:email_domain_blocks: leger informationes sensibile de tote le blocadas de dominio email + admin:read:ip_blocks: leger informationes sensibile de tote le blocadas de IP + admin:read:reports: leger information sensibile de tote le reportos e contos signalate admin:write: modificar tote le datos in le servitor + admin:write:accounts: exequer action de moderation sur contos + admin:write:canonical_email_blocks: exequer actiones de moderation sur blocadas de email canonic + admin:write:domain_allows: exequer actiones de moderation sur dominios permittite + admin:write:domain_blocks: exequer actiones de moderation sur blocadas de dominio + admin:write:email_domain_blocks: exequer actiones de moderation sur blocadas de dominio email + admin:write:ip_blocks: exequer actiones de moderation sur blocadas de IP + admin:write:reports: exequer action de moderation sur reportos + crypto: usar cryptation de extremo-a-extremo follow: modificar relationes del contos + push: reciper tu notificationes push read: leger tote le datos de tu conto read:accounts: vider informationes de conto + read:blocks: vider tu blocadas read:bookmarks: vider tu marcapaginas read:favourites: vider tu favoritos read:filters: vider tu filtros read:follows: vider tu sequites read:lists: vider tu listas read:me: leger solmente le information basic de tu conto + read:mutes: vider tu silentiates read:notifications: vider tu notificationes read:reports: vider tu reportos + read:search: cercar in tu nomine read:statuses: vider tote le messages write: modificar tote le datos de tu conto write:accounts: modificar tu profilo diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index aa3668d92a..302be44112 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -285,6 +285,7 @@ es-AR: update_custom_emoji_html: "%{name} actualizó el emoji %{target}" update_domain_block_html: "%{name} actualizó el bloqueo de dominio para %{target}" update_ip_block_html: "%{name} cambió la regla para la dirección IP %{target}" + update_report_html: "%{name} actualizó la denuncia %{target}" update_status_html: "%{name} actualizó el mensaje de %{target}" update_user_role_html: "%{name} cambió el rol %{target}" deleted_account: cuenta eliminada diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index 6a306b07b0..10806c6b6c 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -285,6 +285,7 @@ es-MX: update_custom_emoji_html: "%{name} actualizó el emoji %{target}" update_domain_block_html: "%{name} actualizó el bloqueo de dominio para %{target}" update_ip_block_html: "%{name} cambió la regla para la IP %{target}" + update_report_html: "%{name} actualizó el informe %{target}" update_status_html: "%{name} actualizó el estado de %{target}" update_user_role_html: "%{name} cambió el rol %{target}" deleted_account: cuenta eliminada diff --git a/config/locales/es.yml b/config/locales/es.yml index e7db7c8b04..840bc2ce9b 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -285,6 +285,7 @@ es: update_custom_emoji_html: "%{name} actualizó el emoji %{target}" update_domain_block_html: "%{name} actualizó el bloqueo de dominio para %{target}" update_ip_block_html: "%{name} cambió la regla para la IP %{target}" + update_report_html: "%{name} actualizó el informe %{target}" update_status_html: "%{name} actualizó la publicación de %{target}" update_user_role_html: "%{name} cambió el rol %{target}" deleted_account: cuenta eliminada diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 5f96f611b4..53db0232aa 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -285,6 +285,7 @@ fi: update_custom_emoji_html: "%{name} päivitti emojin %{target}" update_domain_block_html: "%{name} päivitti verkkotunnuksen %{target} eston" update_ip_block_html: "%{name} muutti sääntöä IP-osoitteelle %{target}" + update_report_html: "%{name} päivitti raportin %{target}" update_status_html: "%{name} päivitti käyttäjän %{target} julkaisun" update_user_role_html: "%{name} muutti roolia %{target}" deleted_account: poisti tilin diff --git a/config/locales/fo.yml b/config/locales/fo.yml index f7303c512a..57caff4d71 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -285,6 +285,7 @@ fo: update_custom_emoji_html: "%{name} dagførdi kensluteknið %{target}" update_domain_block_html: "%{name} dagførdi navnaøkisblokeringina hjá %{target}" update_ip_block_html: "%{name} broytti IP-reglurnar %{target}" + update_report_html: "%{name} dagførdi meldingina %{target}" update_status_html: "%{name} dagførdi postin hjá %{target}" update_user_role_html: "%{name} broyttir %{target} leiklutir" deleted_account: strikað konta diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 57af7c82c0..2c85dc89ae 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -285,6 +285,7 @@ gl: update_custom_emoji_html: "%{name} actualizou o emoji %{target}" update_domain_block_html: "%{name} actualizou o bloqueo do dominio para %{target}" update_ip_block_html: "%{name} cambiou a regra para IP %{target}" + update_report_html: "%{name} actualizou a denuncia %{target}" update_status_html: "%{name} actualizou a publicación de %{target}" update_user_role_html: "%{name} cambiou o rol %{target}" deleted_account: conta eliminada diff --git a/config/locales/he.yml b/config/locales/he.yml index 14da27ec75..3613a9f0b3 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -291,6 +291,7 @@ he: update_custom_emoji_html: "%{name} עדכן/ה אמוג'י %{target}" update_domain_block_html: "%{name} עדכן/ה חסימת דומיין עבור %{target}" update_ip_block_html: "%{name} שינה כלל עבור IP %{target}" + update_report_html: '%{name} עדכן/ה דו"ח %{target}' update_status_html: "%{name} עדכן/ה הודעה של %{target}" update_user_role_html: "%{name} שינה את התפקיד של %{target}" deleted_account: חשבון מחוק diff --git a/config/locales/hu.yml b/config/locales/hu.yml index c48d527caf..dd57830515 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -285,6 +285,7 @@ hu: update_custom_emoji_html: "%{name} frissítette az emodzsit: %{target}" update_domain_block_html: "%{name} frissítette a %{target} domain tiltását" update_ip_block_html: "%{name} módosította a(z) %{target} IP-címre vonatkozó szabályt" + update_report_html: "%{name} frissítette a %{target} bejelentést" update_status_html: "%{name} frissítette %{target} felhasználó bejegyzését" update_user_role_html: "%{name} módosította a(z) %{target} szerepkört" deleted_account: törölt fiók diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 68676a09f7..8af676454f 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -285,6 +285,7 @@ ia: update_custom_emoji_html: "%{name} actualisava le emoticone %{target}" update_domain_block_html: "%{name} actualisava le blocada de dominio pro %{target}" update_ip_block_html: "%{name} cambiava le regula pro IP %{target}" + update_report_html: "%{name} actualisava le reporto %{target}" update_status_html: "%{name} actualisava le message per %{target}" update_user_role_html: "%{name} cambiava le rolo de %{target}" deleted_account: conto delite @@ -973,6 +974,7 @@ ia: webhook: Crocs web admin_mailer: auto_close_registrations: + body: Per un carentia recente de activate de moderator, le registrationes sur %{instance} ha essite automaticamente mutate a besoniante revision manual, pro impedir %{instance} de esser usate como un platteforma pro potential mal actores. Tu pote mutar lo retro pro sempre aperir le registrationes. subject: Le registrationes pro %{instance} ha essite automaticamente mutate a besoniante de approbation new_appeal: actions: @@ -1054,19 +1056,27 @@ ia: clicking_this_link: cliccante iste ligamine login_link: acceder proceed_to_login_html: Ora tu pote continuar a %{login_link}. + redirect_to_app_html: Tu deberea haber essite re-dirigite al app %{app_name}. Si isto non eveni, tenta %{clicking_this_link} o manualmente retorna al app. + registration_complete: Tu registration sur %{domain} es ora complete! welcome_title: Benvenite, %{name}! + wrong_email_hint: Si ille adresse email non es correcte, tu pote cambiar lo in parametros de conto. delete_account: Deler le conto + delete_account_html: Si tu vole a dele tu conto, tu pote continuar ci. Te sera demandate confirmation. description: + prefix_invited_by_user: "@%{name} te invita a junger te a iste servitor de Mastodon!" prefix_sign_up: Inscribe te sur Mastodon hodie! + suffix: Con un conto, tu potera sequer personas, messages de actualisation e excambios de messages con usatores de ulle servitor de Mastodon e plus! didnt_get_confirmation: Non recipeva tu un ligamine de confirmation? dont_have_your_security_key: Non ha tu le clave de securitate? forgot_password: Contrasigno oblidate? invalid_reset_password_token: Pete un nove. + link_to_otp: Insere un codice a duo factores o un codice de recuperation ab tu telephono link_to_webauth: Usa tu apparato clave de securitate log_in_with: Accede con login: Accede logout: Clauder le session migrate_account: Move a un conto differente + migrate_account_html: Si tu vole re-adressar iste conto a un altere, tu pote configurar lo ci. or_log_in_with: O accede con privacy_policy_agreement_html: Io ha legite e acceptar le politica de confidentialitate progress: @@ -1192,6 +1202,7 @@ ia: invalid_domain: non es un nomine de dominio valide edit_profile: basic_information: Information basic + hint_html: "Personalisa lo que le personas vide sur tu profilo public e presso tu messages. Il es plus probabile que altere personas te seque e interage con te quando tu ha un profilo compilate e un photo de profilo." other: Alteres errors: '400': Le requesta que tu inviava era non valide o mal formate. @@ -1230,6 +1241,7 @@ ia: add_new: Adder nove errors: limit: Tu ha jam consiliate le maxime numero de hashtags + hint_html: "Consilia tu plus importante hashtags sur tu profilo. Un grande instrumento pro tener tracia de tu labores creative e projectos de longe-tempore, le hashtags consiliate es monstrate prominentemente sur tu profilo e permitte accesso rapide a tu proprie messages." filters: contexts: account: Profilos @@ -1241,8 +1253,10 @@ ia: add_keyword: Adder parola clave keywords: Parolas clave statuses: Messages individual + statuses_hint_html: Iste filtro se applica a seliger messages singule sin reguardo si illes concorda le parolas clave infra. Revide o remove le messages ab le filtro. title: Modificar filtro errors: + deprecated_api_multiple_keywords: Iste parametros non pote esser cambiate ab iste application perque illos se applica a plus que un sol parola clave del filtro. Usa un application plus recente o le interfacie web. invalid_context: Nulle o non valide contexto supplite index: contexts: Filtros in %{contexts} @@ -1272,6 +1286,12 @@ ia: title: Messages filtrate generic: all: Toto + all_items_on_page_selected_html: + one: "%{count} elemento sur iste pagina es seligite." + other: Tote le %{count} elementos sur iste pagina es seligite. + all_matching_items_selected_html: + one: "%{count} elemento concordante que tu cerca es seligite." + other: Tote le %{count} elementos concordante que tu cerca es seligite. cancel: Cancellar changes_saved_msg: Cambios salveguardate con successo! confirm: Confirmar @@ -1299,13 +1319,24 @@ ia: imported: Importate mismatched_types_warning: Il appare que tu pote haber seligite le typo errate pro iste importation, controla duo vices. modes: + merge: Funder + merge_long: Mantene le registrationes existente e adde illos nove + overwrite: Superscriber overwrite_long: Reimplaciar registros actual con le noves overwrite_preambles: blocking_html: Tu es sur le puncto de reimplaciar tu lista de blocadas per usque a %{total_items} contos proveniente de %{filename}. + bookmarks_html: Tu va reimplaciar tu lista de blocadas per usque a %{total_items} contos proveniente de %{filename}. domain_blocking_html: Tu es sur le puncto de reimplaciar tu lista de blocadas de dominio per usque a %{total_items} dominios proveniente de %{filename}. + following_html: Tu va sequer usque %{total_items} contos de %{filename} e cessar de sequer ulle altere. + lists_html: Tu va reimplaciar tu lista con contentos de %{filename}. Usque %{total_items} contos sera addite a nove listas. + muting_html: Tu va reimplaciar tu lista de contos silentiate con usque %{total_items} contos ab %{filename}. preambles: blocking_html: Tu es sur le puncto de blocar usque a %{total_items} contos a partir de %{filename}. + bookmarks_html: Tu va adder usque %{total_items} messages de %{filename} a tu marcapaginas. domain_blocking_html: Tu es sur le puncto de blocar usque a %{total_items} dominios a partir de %{filename}. + following_html: Tu va blocar usque a %{total_items} dominios ab %{filename}. + lists_html: Tu va adder usque %{total_items} contos ab %{filename} a tu lista. Nove listas sera create si il non ha lista a adder. + muting_html: Tu va silentiar usque %{total_items} contos ab %{filename}. preface: Tu pote importar datos que tu ha exportate de un altere servitor, como un lista de personas que tu seque o bloca. recent_imports: Importationes recente states: @@ -1348,16 +1379,30 @@ ia: expires_in_prompt: Nunquam generate: Generar ligamine de invitation invalid: Iste invitation non es valide + invited_by: 'Tu ha essite invitate per:' max_uses: one: un uso other: "%{count} usos" + max_uses_prompt: Nulle limite + prompt: Genera e comparti ligamines con alteres pro conceder accesso a iste servitor table: expires_at: Expira + uses: Usos title: Invitar personas + lists: + errors: + limit: Tu ha attingite le maxime numero de listas login_activities: authentication_methods: + otp: app pro authentication a duo factores password: contrasigno + sign_in_token: codice de securitate de e-mail webauthn: claves de securitate + description_html: Si tu vide activitate que tu non recognosce, considera de cambiar tu contrasigno e activar le authentication a duo factores. + empty: Nulle chronologia de authentication disponibile + failed_sign_in_html: Tentativa de authentication fallite con %{method} ab %{ip} (%{browser}) + successful_sign_in_html: Apertura de session con successo con %{method} ab %{ip} (%{browser}) + title: Chronologia de authentication mail_subscriptions: unsubscribe: action: Si, desubscriber @@ -1373,32 +1418,110 @@ ia: resubscribe_html: Si tu ha cancellate le subscription in error, tu pote resubscriber te a partir del parametros de notification in e-mail. success_html: Tu non recipera plus %{type} pro Mastodon sur %{domain} a tu adresse de e-mail %{email}. title: Desubcriber + media_attachments: + validations: + images_and_video: Impossibile annexar un video a un message que jam contine imagines + not_ready: Impossibile annexar un video a un message que jam contine imagines. Retenta post un momento! + too_many: Impossibile annexar plus que 4 files migrations: + acct: Movite a + cancel: Cancellar redirection + cancel_explanation: Cancellar le redirection reactivara tu conto actual, ma non reportara sequaces que ha essite movite in ille conto. + cancelled_msg: Redirection cancellate con successo. errors: + already_moved: is the same account you have already moved to + missing_also_known_as: non es un alias de iste conto move_to_self: non pote esser le conto actual not_found: non poterea esser trovate + on_cooldown: Tu es in pausa + followers_count: Sequaces a tempore de mover + incoming_migrations: Movente ab un conto differente + incoming_migrations_html: Pro mover ab un altere conto a isto, primo tu debe crear un alias de conto. + moved_msg: Tu conto ora es redirigite a %{acct} e tu sequaces es movite super. + not_redirecting: Tu conto actualmente non es redirigite a ulle altere conto. + on_cooldown: Tu recentemente ha migrate tu conto. Iste function de novo sera disponibile in %{count} dies. + past_migrations: Migrationes passate + proceed_with_move: Mover sequaces + redirected_msg: Tu conto es ora redirigite a %{acct}. + redirecting_to: Tu conto es redirigite a %{acct}. + set_redirect: Predefinir redirection + warning: + backreference_required: Le nove conto debe primo esser configurate pro referer se a isto + before: 'Ante de continuar, lege iste notas accuratemente:' + cooldown: Post le movimento il ha un periodo de pausa durante le qual tu non potera mover te ancora + disabled_account: Tu conto actual non sera plenmente usabile postea. Comocunque, tu habera accesso a exportation de datos e re-activation. + followers: Iste action movera tote le sequaces ab le conto actual al nove conto + only_redirect_html: In alternativa, tu pote solo superponer un redirection sur tu profilo. + other_data: Nulle altere datos sera movite automaticamente + redirect: Le profilo de tu conto actual sera actualisate con un aviso de redirection e sera excludite de recercas moderation: title: Moderation move_handler: carry_blocks_over_text: Iste usator ha cambiate de conto desde %{acct}, que tu habeva blocate. + carry_mutes_over_text: Iste usator moveva ab %{acct}, que tu habeva silentiate. + copy_account_note_text: 'Iste usator moveva ab %{acct}, ci era tu previe notas re ille:' + navigation: + toggle_menu: Mutar menu notification_mailer: admin: + report: + subject: "%{name} inviava un reporto" sign_up: subject: "%{name} se ha inscribite" + favourite: + body: 'Tu message era favorite per %{name}:' + subject: "%{name} favoriva tu message" + title: Nove preferito follow: + body: "%{name} ora te seque!" + subject: "%{name} ora te seque" title: Nove sequitor follow_request: + action: Gere requestas de sequer + body: "%{name} ha demandate de sequer te" + subject: 'Sequace pendente: %{name}' title: Nove requesta de sequimento mention: action: Responder + body: 'Tu era mentionate per %{name} in:' + subject: Tu ha essite mentionate per %{name} title: Nove mention poll: subject: Un inquesta de %{name} ha finite + reblog: + body: 'Tu message ha essite impulsate per %{name}:' + subject: "%{name} ha impulsate tu message" + title: Nove impulso + status: + subject: "%{name} justo ha publicate" + update: + subject: "%{name} ha modificate un message" + notifications: + administration_emails: Avisos de email per administrator + email_events: Eventos pro avisos de email + email_events_hint: 'Selige eventos pro que tu vole reciper avisos:' + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T otp_authentication: + code_hint: Insere le codice generate per tu app de authentication pro confirmar + description_html: Si tu activa le authentication a duo factores per un app de authentication, le authentication requirera que tu es in possession de tu telephono, que generara testimonios pro facer te entrar. enable: Activar + instructions_html: "Scande iste codice QR in Google Authenticator o un simile app TOTP sur tu telephono. Desde ora in avante, ille app generara testimonios que tu debera inserer quando tu te authenticara." + manual_instructions: 'Si tu non pote scander le codice QR e besonia de inserer lo manualmente, ecce le texto-simple secrete:' setup: Configurar + wrong_code: Le codice inserite non era valide! Es tempore de servitor e tempore de apparato correcte? pagination: + newer: Plus recente next: Sequente + older: Plus vetere prev: Previe truncate: "…" polls: @@ -1418,9 +1541,13 @@ ia: posting_defaults: Publicationes predefinite public_timelines: Chronologias public privacy: + hint_html: "Personalisa como tu vole que tu profilo e tu messages a es trovate. Un varietate de functiones in Mastodon pote adjutar te attinger un plus large auditorio si activate. Prende un momento pro revider iste parametros pro assecurar te que illos se adapta a tu caso de uso." privacy: Confidentialitate + privacy_hint_html: Controla quanto tu vole divulgar pro le beneficio de alteres. Le gente discoperi profilos e applicationes interessante percurrente le profilos sequite per altere personas e vidente a partir de qual applicationes illos publica lor messages, ma tu pote preferer de mantener tal information private. reach: Portata + reach_hint_html: Controla si tu vole esser discoperite e sequite per nove personas. Vole tu que tu messages appare sur le schermo Explorar? Vole tu que altere personas te vide in lor recommendationes de sequimento? Vole tu acceptar automaticamente tote le nove sequitores o prefere tu haber le controlo granular super cata un? search: Cercar + search_hint_html: Controla como tu vole esser trovate. Vole tu que le gente te trova per medio del contento de tu messages public? Vole tu que personas foras de Mastodon trova tu profilo quando illes cerca in le web? Nota ben que non es possibile garantir le exclusion total de tu information public del motores de recerca. title: Confidentialitate e portata privacy_policy: title: Politica de confidentialitate @@ -1521,35 +1648,96 @@ ia: aliases: Aliases de conto appearance: Apparentia authorized_apps: Apps autorisate + back: Tornar a Mastodon delete: Deletion de conto development: Disveloppamento edit_profile: Modificar profilo + export: Exportation de datos featured_tags: Hashtags eminente import: Importar + import_and_export: Importar e exportar migrate: Migration de conto notifications: Notificationes de e-mail preferences: Preferentias profile: Profilo public relationships: Sequites e sequitores + severed_relationships: Relationes rupte + statuses_cleanup: Deletion de message automatic strikes: Admonitiones de moderation + two_factor_authentication: Authentication a duo factores + webauthn_authentication: Claves de securitate severed_relationships: download: Discargar (%{count}) event_type: account_suspension: Suspension del conto (%{target_name}) domain_block: Suspension del servitor (%{target_name}) user_domain_block: Tu ha blocate %{target_name} + lost_followers: Sequitores perdite + lost_follows: Sequites perdite preamble: Tu pote perder sequites e sequitores quando tu bloca un dominio o quando tu moderatores decide suspender un servitor remote. Quando isto occurre, tu potera discargar listas de relationes rumpite, a inspectar e eventualmente importar in un altere servitor. + purged: Le information re iste servitor ha essite purgate per le administratores de tu servitor. type: Evento statuses: + attached: + audio: + one: "%{count} audio" + other: "%{count} audio" + description: 'Attachate: %{attached}' + image: + one: "%{count} imagine" + other: "%{count} imagines" + video: + one: "%{count} video" + other: "%{count} videos" + boosted_from_html: Impulsate desde %{acct_link} + content_warning: 'Advertimento de contento: %{warning}' + default_language: Mesme como lingua de interfacie + disallowed_hashtags: + one: 'contineva un hashtag non autorisate: %{tags}' + other: 'contineva le hashtags non autorisate: %{tags}' + edited_at_html: Modificate le %{date} + errors: + in_reply_not_found: Le message a que tu tenta responder non pare exister. open_in_web: Aperir in le web + over_character_limit: limite de characteres de %{max} excedite + pin_errors: + direct: Messages que es solo visibile a usatores mentionate non pote esser appunctate + limit: Tu ha jam appunctate le maxime numero de messages + ownership: Le message de alcuno altere non pote esser appunctate + reblog: Un impulso non pote esser affixate poll: + total_people: + one: "%{count} persona" + other: "%{count} personas" + total_votes: + one: "%{count} voto" + other: "%{count} votos" vote: Votar show_more: Monstrar plus + show_thread: Monstrar argumento + title: '%{name}: "%{quote}"' visibilities: direct: Directe + private: Solo-sequaces private_long: Solmente monstrar a sequitores public: Public + public_long: Omnes pote vider + unlisted: Non listate + unlisted_long: Omnes pote vider, ma non es listate in le chronologias public statuses_cleanup: + enabled: Deler automaticamente le messages ancian + enabled_hint: Dele automaticamente tu messages un vice que illos attinge un limine de etate specificate, salvo que illes concorda un del exceptiones infra + exceptions: Exceptiones + explanation: Pois que deler messages es un operation costose, isto es facite lentemente in le tempore quando le servitor non es alteremente occupate. Pro iste ration, tu messages pote esser delite un poco post que illos attinge le limine de etate. + ignore_favs: Ignorar favoritos + ignore_reblogs: Ignorar impulsos + interaction_exceptions: Exceptiones basate super interactiones + interaction_exceptions_explanation: Nota que il non ha garantia que le messages essera delite si illos va sub le limine de favorites o impulsos post haber lo superate un vice. + keep_direct: Mantener le messages directe + keep_direct_hint: Non dele alcuno de tu messages directe + keep_media: Mantener messages con annexos de medios + keep_media_hint: Non dele alcuno de tu messages que ha annexos de medios + keep_pinned: Mantener messages appunctate keep_pinned_hint: Non dele alcuno de tu messages appunctate keep_polls: Mantener sondages keep_polls_hint: Non dele ulle de tu sondages @@ -1567,32 +1755,94 @@ ia: '63113904': 2 annos '7889238': 3 menses min_age_label: Limine de etate + min_favs: Mantener messages favorite al minus + min_favs_hint: Non deler alcuno de tu messages que ha recipite al minus iste numero de favoritos. Lassar blanc pro deler messages sin reguardo de lor numero de favoritos + min_reblogs: Mantener messages impulsate al minus + min_reblogs_hint: Non dele alcun de tu messages que ha essite impulsate al minus iste numero de vices. Lassar vacue pro deler messages independentemente de lor numero de impulsos stream_entries: sensitive_content: Contento sensibile strikes: errors: too_late: Es troppo tarde pro facer appello contra iste admonition + tags: + does_not_match_previous_name: non concorda le nomine previe themes: contrast: Mastodon (Alte contrasto) default: Mastodon (Obscur) mastodon-light: Mastodon (Clar) system: Automatic (usar thema del systema) + time: + formats: + default: "%d %b %Y, %H:%M" + month: "%b %Y" + time: "%H:%M" + with_time_zone: "%b %d, %Y, %H:%M %Z" + translation: + errors: + quota_exceeded: Le quota de utilisation del servitor pro le servicio de traduction ha essite excedite. + too_many_requests: Il ha habite troppe requestas al servicio de traduction recentemente. two_factor_authentication: add: Adder disable: Disactivar 2FA + disabled_success: Authentication a duo factores disactivate con successo edit: Modificar + enabled: Le authentication a duo factores es activate + enabled_success: Authentication a duo factores activate con successo generate_recovery_codes: Generar codices de recuperation + lost_recovery_codes: Le codices de recuperation te permitte de reganiar accesso a tu conto si tu perde tu telephono. Si tu ha perdite tu codices de recuperation, tu pote regenerar los ci. Tu vetere codices de recuperation sera invalidate. + methods: Methodos a duo factores + otp: App de authenticator + recovery_codes: Salveguardar codices de recuperation + recovery_codes_regenerated: Codices de recuperation regenerate con successo + recovery_instructions_html: Si tu perde le accesso a tu telephono, tu pote usar un del codices de recuperation hic infra pro reganiar le accesso a tu conto. Mantene le codices de recuperation secur. Per exemplo, tu pote imprimer los e guardar los con altere documentos importante. + webauthn: Claves de securitate user_mailer: appeal_approved: action: Parametros de conto explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite approbate. Tu conto ha de novo un bon reputation. + subject: Tu appello ab %{date} ha essite approbate + subtitle: Tu conto es ancora un vice in regula. + title: Appello approbate appeal_rejected: explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite rejectate. + subject: Tu appello ab %{date} ha essite rejectate + subtitle: Tu appello ha essite rejectate. + title: Appello rejectate + backup_ready: + explanation: Tu ha requestate un copia de securitate complete de tu conto de Mastodon. + extra: Isto es preste pro discargar! + subject: Tu archivo es preste pro discargar + title: Discargar archivo + failed_2fa: + details: 'Hic es le detalios del tentativa de initio de session:' + explanation: Alcuno ha tentate aperir session a tu conto ma ha fornite un secunde factor de authentication non valide. + further_actions_html: Si non se tractava de te, nos recommenda %{action} immediatemente perque illo pote esser compromittite. + subject: Fallimento del authentication de duo factores + title: Falleva le authentication de duo factores + suspicious_sign_in: + change_password: cambiar tu contrasigno + details: 'Hic es le detalios del initio de session:' + explanation: Nos ha detegite un initio de session a tu conto ab un nove adresse IP. + further_actions_html: Si non se tractava de te, nos recommenda %{action} immediatemente e activar le authentication bifactorial pro mantener tu conto secur. + subject: Alcuno ha accedite a tu conto desde un nove adresse IP + title: Un nove initio de session warning: appeal: Submitter un appello + appeal_description: Si tu crede que se tracta de un error, tu pote presentar un appello al personal de %{instance}. categories: spam: Spam + violation: Le contento viola le sequente regulas del communitate + explanation: + delete_statuses: Alcunes de tu messages ha essite judicate contrari a un o plus directivas communitari e ha dunque essite removite per le moderatores de %{instance}. + disable: Tu non pote plus usar tu conto, ma tu profilo e altere datos remane intacte. Tu pote requestar un copia de reserva de tu datos, cambiar le parametros del conto o deler le conto. + mark_statuses_as_sensitive: Alcunes de tu messages ha essite marcate como sensibile per le moderatores de %{instance}. Isto vole dicer que le gente debe toccar le objectos multimedial in le messages ante que un previsualisation appare. Tu pote marcar objectos multimedial como sensibile tu mesme quando tu publica messages in futuro. + sensitive: A partir de iste momento, tote le files multimedial que tu incarga essera marcate como sensibile e le gente debera cliccar sur un advertimento ante de poter vider los. + silence: Tu pote ancora usar tu conto ma solmente le personas qui ja te seque videra tu messages sur iste servitor, e tu pote esser excludite de varie functiones de discoperta. Nonobstante, altere personas pote ancora sequer te manualmente. + suspend: Tu non pote plus usar tu conto, e tu profilo e altere datos non es plus accessibile. Tu pote ancora aperir session pro requestar un copia de reserva de tu datos usque lor elimination in circa 30 dies. Nos retenera certe datos de base pro impedir que tu evade le suspension. + reason: 'Ration:' + statuses: 'Message citate:' subject: + delete_statuses: Tu messages sur %{acct} esseva removite disable: Tu conto %{acct} ha essite gelate mark_statuses_as_sensitive: Tu messages sur %{acct} ha essite marcate como sensibile none: Advertimento pro %{acct} @@ -1612,20 +1862,71 @@ ia: apps_ios_action: Discargar sur le App Store apps_step: Discarga nostre applicationes official. apps_title: Applicationes de Mastodon + checklist_subtitle: 'Comencia tu aventura sur le web social:' + checklist_title: Prime passos edit_profile_action: Personalisar edit_profile_step: Impulsa tu interactiones con un profilo comprehensive. edit_profile_title: Personalisar tu profilo explanation: Ecce alcun consilios pro initiar feature_action: Apprender plus + feature_audience: Mastodon te presenta le possibilitate unic de gerer tu audientia sin intermediarios. Mastodon, installate sur tu proprie infrastructura, te permitte sequer, e esser sequite per, personas sur qualcunque altere servitor Mastodon in linea, e necuno lo controla salvo tu. feature_audience_title: Crea tu auditorio in fiducia + feature_control: Tu sape melio lo que tu vole vider sur tu fluxo de initio. Nulle algorithmos o annuncios dissipa tu tempore. Seque quicinque sur qualcunque servitor Mastodon desde un sol conto, recipe lor messages in ordine chronologic, e face te un angulo del internet ubi tu te senti a casa. + feature_control_title: Mantene le controlo de tu proprie chronologia + feature_creativity: Mastodon supporta messages con audio, video e imagines, descriptiones de accessibilitate, sondages, advertimentos de contento, avatares con animation, emojis personalisate, controlo de retalio de miniaturas, e plus, pro adjutar te a exprimer te in linea. Que tu publica tu arte, tu musica o tu podcast, Mastodon existe pro te. + feature_creativity_title: Creativitate sin parallel + feature_moderation: Mastodon remitte le controlo in tu manos. Cata servitor crea su proprie regulas e directivas, applicate localmente e non de maniera vertical como le medios social corporative, rendente lo flexibile in responder al necessitates de differente gruppos de personas. Adhere a un servitor con regulas que te place, o alberga le tue. feature_moderation_title: Moderation como deberea esser follow_action: Sequer + follow_step: Sequer personas interessante es le ration de esser de Mastodon. + follow_title: Personalisa tu fluxo de initio + follows_subtitle: Seque contos popular + follows_title: Qui sequer + follows_view_more: Vider plus de personas a sequer + hashtags_recent_count: + one: "%{people} persona in le passate duo dies" + other: "%{people} personas in le passate duo diea" + hashtags_subtitle: Explora le tendentias del passate 2 dies + hashtags_title: Hashtags in tendentia + hashtags_view_more: Vider plus de hashtags in tendentia + post_action: Scriber + post_step: Saluta le mundo con texto, photos, videos o sondages. post_title: Face tu prime message share_action: Compartir + share_step: Face saper a tu amicos como trovar te sur Mastodon. share_title: Compartir tu profilo de Mastodon + sign_in_action: Initiar session subject: Benvenite in Mastodon + title: Benvenite a bordo, %{name}! + users: + follow_limit_reached: Tu non pote sequer plus de %{limit} personas + go_to_sso_account_settings: Vader al parametros de conto de tu fornitor de identitate + invalid_otp_token: Codice de duo factores non valide + otp_lost_help_html: Si tu ha perdite le accesso a ambes, tu pote contactar %{email} + rate_limited: Troppo de tentativas de authentication. Per favor reessaya plus tarde. + seamless_external_login: Tu ha aperite session per medio de un servicio externe. Le parametros de contrasigno e de e-mail es dunque indisponibile. + signed_in_as: 'Session aperite como:' verification: + extra_instructions_html: Consilio: Le ligamine sur tu sito web pote esser invisibile. Le parte importante es rel="me" que impedi le usurpation de identitate sur sitos web con contento generate per usatores. Tu pote mesmo usar un etiquetta link in le capite del pagina in vice de a, ma le codice HTML debe esser accessibile sin executar JavaScript. + here_is_how: Ecce como + hint_html: "Omnes pote verificar lor identitate sur Mastodon. Isto es basate sur standards web aperte e es gratuite, ora e pro sempre. Tote lo que es necessari es un sito web personal que le gente recognosce como le tue. Quando tu liga a iste sito web desde tu profilo, le systema verificara que le sito web liga retro a tu profilo e monstrara un indicator visual de iste facto." + instructions_html: Copia e colla le codice hic infra in le HTML de tu sito web. Alora adde le adresse de tu sito web in un del campos supplementari sur tu profilo desde le scheda “Modificar profilo” e salva le cambiamentos. + verification: Verification verified_links: Tu ligamines verificate webauthn_credentials: add: Adder un nove clave de securitate + create: + error: Il habeva un problema in adder tu clave de securitate. Tenta novemente. + success: Tu clave de securitate ha essite addite con successo. delete: Deler + delete_confirmation: Es tu secur que tu vole deler iste clave de securitate? + description_html: Si tu activa le authentication per clave de securitate, le apertura de session requirera que tu usa un de tu claves de securitate. + destroy: + error: Il habeva un problema in deler tu clave de securitate. Tenta novemente. + success: Tu clave de securitate ha essite delite con successo. + invalid_credential: Clave de securitate non valide + nickname_hint: Insere le pseudonymo de tu nove clave de securitate + not_enabled: Tu ancora non ha activate WebAuthn + not_supported: Iste navigator non supporta claves de securitate + otp_required: Pro usar le claves de securitate activa prime le authentication de duo factores. + registered_on: Registrate le %{date} diff --git a/config/locales/it.yml b/config/locales/it.yml index bda681ac08..5b75e7af7d 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -285,6 +285,7 @@ it: update_custom_emoji_html: "%{name} ha aggiornato emoji %{target}" update_domain_block_html: "%{name} ha aggiornato il blocco dominio per %{target}" update_ip_block_html: "%{name} ha cambiato la regola per l'IP %{target}" + update_report_html: "%{name} ha aggiornato la segnalazione %{target}" update_status_html: "%{name} ha aggiornato lo status di %{target}" update_user_role_html: "%{name} ha modificato il ruolo %{target}" deleted_account: account eliminato diff --git a/config/locales/ko.yml b/config/locales/ko.yml index f3f3e3a8fb..b104e31fc0 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -282,6 +282,7 @@ ko: update_custom_emoji_html: "%{name} 님이 에모지 %{target}를 업데이트 했습니다" update_domain_block_html: "%{name} 님이 %{target}에 대한 도메인 차단을 갱신했습니다" update_ip_block_html: "%{name} 님이 IP 규칙 %{target}을 수정했습니다" + update_report_html: "%{name} 님이 신고 %{target}를 업데이트 했습니다" update_status_html: "%{name} 님이 %{target}의 게시물을 업데이트했습니다" update_user_role_html: "%{name} 님이 %{target} 역할을 수정했습니다" deleted_account: 계정을 삭제했습니다 diff --git a/config/locales/lad.yml b/config/locales/lad.yml index e9f18d4bed..9c165472cd 100644 --- a/config/locales/lad.yml +++ b/config/locales/lad.yml @@ -285,6 +285,7 @@ lad: update_custom_emoji_html: "%{name} aktualizo el emoji %{target}" update_domain_block_html: "%{name} aktualizo el bloko de domeno para %{target}" update_ip_block_html: "\"%{name} troko la regla de IP %{target}" + update_report_html: "%{name} aktualizo el raporto %{target}" update_status_html: "%{name} aktualizo la publikasyon de %{target}" update_user_role_html: "%{name} troko el rolo %{target}" deleted_account: kuento supremido diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 74dea29b0e..3452f80994 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -285,6 +285,7 @@ nl: update_custom_emoji_html: Emoji %{target} is door %{name} bijgewerkt update_domain_block_html: "%{name} heeft de domeinblokkade bijgewerkt voor %{target}" update_ip_block_html: "%{name} wijzigde de IP-regel voor %{target}" + update_report_html: Rapportage %{target} is door %{name} bijgewerkt update_status_html: "%{name} heeft de berichten van %{target} bijgewerkt" update_user_role_html: "%{name} wijzigde de rol %{target}" deleted_account: verwijderd account diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 7c037d7d00..1c3fda8d03 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -291,6 +291,7 @@ pl: update_custom_emoji_html: Zaktualizowane emoji %{target} przez %{name} update_domain_block_html: Zaktualizowano blokadę domeny dla %{target} przez %{name} update_ip_block_html: "%{name} stworzył(a) regułę dla IP %{target}" + update_report_html: "%{target} zaktualizowany przez %{name}" update_status_html: "%{name} zaktualizował(a) wpis użytkownika %{target}" update_user_role_html: "%{name} zmienił rolę %{target}" deleted_account: usunięte konto diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 0c2e6cfd6d..b4669e24d8 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -285,6 +285,7 @@ pt-PT: update_custom_emoji_html: "%{name} atualizou o emoji %{target}" update_domain_block_html: "%{name} atualizou o bloqueio de domínio para %{target}" update_ip_block_html: "%{name} alterou regra para IP %{target}" + update_report_html: "%{name} atualizou a denúncia %{target}" update_status_html: "%{name} atualizou o estado de %{target}" update_user_role_html: "%{name} alterou a função %{target}" deleted_account: conta apagada diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml index 2f7010bacf..9ac36447de 100644 --- a/config/locales/simple_form.fi.yml +++ b/config/locales/simple_form.fi.yml @@ -78,14 +78,14 @@ fi: form_admin_settings: activity_api_enabled: Paikallisesti julkaistujen julkaisujen, aktiivisten käyttäjien ja rekisteröitymisten viikoittainen määrä app_icon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen mobiililaitteiden sovelluskuvakkeen omalla kuvakkeella. - backups_retention_period: Käyttäjillä on mahdollisuus arkistoida julkaisujaan myöhemmin ladattaviksi. Kun tämä on asetettu positiiviseksi arvoksi, nämä arkistot poistetaan automaattisesti asetetun päivien määrän jälkeen. + backups_retention_period: Käyttäjillä on mahdollisuus arkistoida julkaisujaan myöhemmin ladattaviksi. Kun arvo on positiivinen, nämä arkistot poistuvat automaattisesti, kun määritetty määrä päiviä on kulunut. bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuosituslistojen alkuun. closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu - content_cache_retention_period: Kaikki muiden palvelimien viestit (mukaan lukien tehostukset ja vastaukset) poistetaan määritetyn päivien lukumäärän jälkeen, ottamatta huomioon paikallisen käyttäjän vuorovaikutusta kyseisten viestien kanssa. Sisältää viestit, jossa paikallinen käyttäjä on merkinnyt kirjanmerkiksi tai suosikeiksi. Myös yksityiset maininnat eri käyttäjien välillä menetetään, eikä niitä voi palauttaa. Tämän asetuksen käyttö on tarkoitettu erityisiin tapauksiin ja se rikkoo monia käyttäjien odotuksia, kun se toteutetaan yleistarkoituksiin. + content_cache_retention_period: Kaikki muiden palvelinten julkaisut (mukaan lukien tehostukset ja vastaukset) poistuvat, kun määritetty määrä päiviä on kulunut, ottamatta huomioon paikallisen käyttäjän vuorovaikutusta näiden julkaisujen kanssa. Sisältää julkaisut, jotka paikallinen käyttäjä on merkinnyt kirjanmerkiksi tai suosikiksi. Myös yksityiset maininnat eri palvelinten käyttäjien välillä menetetään, eikä niitä voi palauttaa. Tämä asetus on tarkoitettu käytettäväksi erityistapauksissa ja rikkoo monia käyttäjien odotuksia, kun sitä käytetään yleistarkoituksiin. custom_css: Voit käyttää mukautettuja tyylejä Mastodonin verkkoversiossa. favicon: WEBP, PNG, GIF tai JPG. Korvaa oletusarvoisen Mastodonin suosikkikuvakkeen omalla kuvakkeella. mascot: Ohittaa kuvituksen edistyneessä selainkäyttöliittymässä. - media_cache_retention_period: Mediatiedostot käyttäjien tekemistä viesteistä ovat välimuistissa palvelimellasi. Kun arvo on positiivinen, media poistetaan määritetyn ajan jälkeen. Jos mediaa pyydetään sen poistamisen jälkeen, ne ladataan uudelleen, jos lähdesisältö on vielä saatavilla. Koska linkkien katselun kyselyitä kolmansien osapuolien sivustoille on rajoitettu, on suositeltavaa asettaa tämä arvo vähintään 14 päivään tai linkkien kortteja ei päivitetä pyynnöstä ennen tätä aikaa. + media_cache_retention_period: Käyttäjien tekemien julkaisujen mediatiedostot ovat välimuistissa palvelimellasi. Kun arvo on positiivinen, media poistuu, kun määritetty määrä päiviä on kulunut. Jos mediaa pyydetään sen poistamisen jälkeen, se ladataan uudelleen, jos lähdesisältö on vielä saatavilla. Koska linkkien esikatselun kyselyitä kolmansien osapuolien sivustoille on rajoitettu, on suositeltavaa asettaa tämä arvo vähintään 14 päivään, tai linkkien kortteja ei päivitetä pyynnöstä ennen tätä ajankohtaa. peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, oletko liitossa tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja federoinnista yleisellä tasolla. profile_directory: Profiilihakemisto lueteloi kaikki käyttäjät, jotka ovat ilmoittaneet olevansa löydettävissä. require_invite_text: Kun rekisteröityminen vaatii manuaalisen hyväksynnän, tee ”Miksi haluat liittyä?” -tekstikentästä pakollinen vapaaehtoisen sijaan diff --git a/config/locales/simple_form.sl.yml b/config/locales/simple_form.sl.yml index a4abb737c0..96b36307a5 100644 --- a/config/locales/simple_form.sl.yml +++ b/config/locales/simple_form.sl.yml @@ -77,10 +77,15 @@ sl: warn: Skrij filtrirano vsebino za opozorilom, ki pomenja naslov filtra form_admin_settings: activity_api_enabled: Številke krajevno objavljenih objav, dejavnih uporabnikov in novih registracij na tedenskih seznamih + app_icon: WEBP, PNG, GIF ali JPG. Zamenja privzeto ikono programa na mobilnih napravah z ikono po meri. + backups_retention_period: Uporabniki lahko ustvarijo arhive svojih objav za kasnejši prenos k sebi. Ko je nastavljeno na pozitivno vrednost, bodo ti arhivi po nastavljenem številu dni samodejno izbrisani. bootstrap_timeline_accounts: Ti računi bodo pripeti na vrh priporočenih sledenj za nove uporabnike. closed_registrations_message: Prikazano, ko so registracije zaprte + content_cache_retention_period: Vse objave z drugih strežnikov (vključno z izpostavitvami in odgovori) bodo izbrisani po nastavljenem številu dni, ne glede na krajevne interakcije s temi objavami. To vključuje objave, ki jih je krajevni uporabnik dodal med zaznamke ali priljubljene. Zasebne omembe med uporabniki na različnih strežnikih bodo prav tako izgubljene in jih ne bo moč obnoviti. Uporaba te nastavitve je namenjena strežnikom s posebnim namenom in nasprotuje mnogim pričakovanjem uporabnikov na strežnikih za splošni namen. custom_css: Spletni različici Mastodona lahko uveljavite sloge po meri. + favicon: WEBP, PNG, GIF ali JPG. Zamenja privzeto ikono spletne strani Mastodon z ikono po meri. mascot: Preglasi ilustracijo v naprednem spletnem vmesniku. + media_cache_retention_period: Predstavnostne datoteke iz objav uporabnikov na ostalih strežnikih se začasno hranijo na tem strežniku. Ko je nastavljeno na pozitivno vrednost, bodo predstavnostne datoteke izbrisane po nastavljenem številu dni. Če bo predstavnostna datoteka zahtevana po izbrisu, bo ponovno prenešena, če bo vir še vedno na voljo. Zaradi omejitev pogostosti prejemanja predogledov povezav z drugih strani je priporočljivo to vrednost nastaviti na vsaj 14 dni. V nasprotnem predogledi povezav pred tem časom ne bodo osveženi na zahtevo. peers_api_enabled: Seznam imen domen, na katere je ta strežnik naletel v fediverzumu. Sem niso vključeni podatki o tem, ali ste v federaciji z danim strežnikom, zgolj to, ali vaš strežnik ve zanj. To uporabljajo storitve, ki zbirajo statistične podatke o federaciji v splošnem smislu. profile_directory: Imenik profilov izpiše vse uporabnike, ki so dovolili, da so v njem navedeni. require_invite_text: Če registracije zahtevajo ročno potrditev, nastavite vnos besedila pod »Zakaj se želite pridružiti?« za obveznega. @@ -240,6 +245,7 @@ sl: backups_retention_period: Obdobje hrambe arhivov uporabnikov bootstrap_timeline_accounts: Vedno priporočaj te račune novim uporabnikom closed_registrations_message: Sporočilo po meri, ko registracije niso na voljo + content_cache_retention_period: Obdobje hranjenja vsebine z ostalih strežnikov custom_css: CSS po meri mascot: Maskota po meri (opuščeno) media_cache_retention_period: Obdobje hrambe predpomnilnika predstavnosti diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 6c26511ad6..329ce5a29b 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -291,6 +291,7 @@ sl: update_custom_emoji_html: "%{name} je posodobil/a emotikone %{target}" update_domain_block_html: "%{name} je posodobil/a domenski blok za %{target}" update_ip_block_html: "%{name} je spremenil/a pravilo za IP %{target}" + update_report_html: "%{name} je posodobil poročilo %{target}" update_status_html: "%{name} je posodobil/a objavo uporabnika %{target}" update_user_role_html: "%{name} je spremenil/a vlogo %{target}" deleted_account: izbrisan račun diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index b4976f8985..808a10e729 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -288,6 +288,7 @@ sr-Latn: update_custom_emoji_html: "%{name} je ažurirao/-la emodži %{target}" update_domain_block_html: "%{name} je ažurirao/-la blok domena %{target}" update_ip_block_html: "%{name} je promenio/-la IP uslov za %{target}" + update_report_html: "%{name} je ažurirao izveštaj %{target}" update_status_html: "%{name} je ažurirao/-la objavu korisnika %{target}" update_user_role_html: "%{name} je promenio/-la poziciju %{target}" deleted_account: obrisan nalog diff --git a/config/locales/sr.yml b/config/locales/sr.yml index aec6d399d5..f03c6e878a 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -288,6 +288,7 @@ sr: update_custom_emoji_html: "%{name} је ажурирао/-ла емоџи %{target}" update_domain_block_html: "%{name} је ажурирао/-ла блок домена %{target}" update_ip_block_html: "%{name} је променио/-ла IP услов за %{target}" + update_report_html: "%{name} је ажурирао извештај %{target}" update_status_html: "%{name} је ажурирао/-ла објаву корисника %{target}" update_user_role_html: "%{name} је променио/-ла позицију %{target}" deleted_account: обрисан налог diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 11e1fce3fe..9f0de4a723 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -285,6 +285,7 @@ sv: update_custom_emoji_html: "%{name} uppdaterade emoji %{target}" update_domain_block_html: "%{name} uppdaterade domän-block för %{target}" update_ip_block_html: "%{name} ändrade regel för IP %{target}" + update_report_html: "%{name} uppdaterade rapporten %{target}" update_status_html: "%{name} uppdaterade inlägget av %{target}" update_user_role_html: "%{name} ändrade rollen %{target}" deleted_account: raderat konto diff --git a/config/locales/th.yml b/config/locales/th.yml index 56b7bea69a..5711f68ff8 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -282,6 +282,7 @@ th: update_custom_emoji_html: "%{name} ได้อัปเดตอีโมจิ %{target}" update_domain_block_html: "%{name} ได้อัปเดตการปิดกั้นโดเมนสำหรับ %{target}" update_ip_block_html: "%{name} ได้เปลี่ยนกฎสำหรับ IP %{target}" + update_report_html: "%{name} ได้อัปเดตรายงาน %{target}" update_status_html: "%{name} ได้อัปเดตโพสต์โดย %{target}" update_user_role_html: "%{name} ได้เปลี่ยนบทบาท %{target}" deleted_account: บัญชีที่ลบแล้ว @@ -1838,6 +1839,7 @@ th: feature_action: เรียนรู้เพิ่มเติม feature_audience: Mastodon มีความพิเศษที่ให้คุณจัดการผู้รับสารของคุณได้โดยไม่มีตัวกลาง นอกจากนี้ การติดตั้ง Mastodon บนโครงสร้างพื้นฐานของคุณจะทำให้คุณสามารถติดตาม (และติดตามโดย) เซิร์ฟเวอร์ Mastodon แห่งไหนก็ได้ที่ทำงานอยู่ โดยไม่มีใครสามารถควบคุมได้นอกจากคุณ feature_audience_title: สร้างผู้ชมของคุณด้วยความมั่นใจ + feature_control: คุณทราบดีที่สุดถึงสิ่งที่คุณต้องการเห็นในฟีดหน้าแรกของคุณ ไม่มีอัลกอริทึมหรือโฆษณาให้เสียเวลาของคุณ ติดตามใครก็ตามทั่วทั้งเซิร์ฟเวอร์ Mastodon ใด ๆ จากบัญชีเดียวและรับโพสต์ของเขาตามลำดับเวลา และทำให้มุมอินเทอร์เน็ตของคุณเป็นเหมือนคุณมากขึ้นอีกนิด feature_control_title: การควบคุมเส้นเวลาของคุณเอง feature_creativity_title: ความคิดสร้างสรรค์ที่ไม่มีใครเทียบได้ feature_moderation_title: การกลั่นกรองในแบบที่ควรจะเป็น diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 7b9cf50aaf..469f2c5ad8 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -285,6 +285,7 @@ tr: update_custom_emoji_html: "%{name}, %{target} emojisini güncelledi" update_domain_block_html: "%{name}, %{target} alan adının engelini güncelledi" update_ip_block_html: "%{name}, %{target} IP adresi için kuralı güncelledi" + update_report_html: "%{name}, %{target} raporunu güncelledi" update_status_html: "%{name}, %{target} kullanıcısının gönderisini güncelledi" update_user_role_html: "%{name}, %{target} rolünü değiştirdi" deleted_account: hesap silindi diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 5d9e881ea4..05f3157ec9 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -282,6 +282,7 @@ vi: update_custom_emoji_html: "%{name} đã cập nhật emoji %{target}" update_domain_block_html: "%{name} cập nhật chặn máy chủ %{target}" update_ip_block_html: "%{name} cập nhật chặn IP %{target}" + update_report_html: "%{name} cập nhật báo cáo %{target}" update_status_html: "%{name} cập nhật tút của %{target}" update_user_role_html: "%{name} đã thay đổi vai trò %{target}" deleted_account: tài khoản đã xóa diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 3140ebdd30..12b6197938 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -282,6 +282,7 @@ zh-CN: update_custom_emoji_html: "%{name} 更新了自定义表情 %{target}" update_domain_block_html: "%{name} 更新了对 %{target} 的域名屏蔽" update_ip_block_html: "%{name} 修改了对 IP %{target} 的规则" + update_report_html: "%{name} 更新了举报 %{target}" update_status_html: "%{name} 刷新了 %{target} 的嘟文" update_user_role_html: "%{name} 更改了 %{target} 角色" deleted_account: 账号已注销 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index cdedd759ea..ac633a201d 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -282,6 +282,7 @@ zh-TW: update_custom_emoji_html: "%{name} 已更新自訂 emoji 表情符號 %{target}" update_domain_block_html: "%{name} 已更新 %{target} 之網域封鎖" update_ip_block_html: "%{name} 已變更 IP %{target} 之規則" + update_report_html: "%{name} 已更新 %{target} 的檢舉" update_status_html: "%{name} 已更新 %{target} 的嘟文" update_user_role_html: "%{name} 已變更 %{target} 角色" deleted_account: 已刪除帳號 From 0ce22859a5f989593b04cc7701521655a2f85480 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 09:56:28 +0200 Subject: [PATCH 199/658] fix(deps): update dependency @rails/ujs to v7.1.3 (#30356) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 773f19c50d..f38076d4c6 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "@formatjs/intl-pluralrules": "^5.2.2", "@gamestdio/websocket": "^0.3.2", "@github/webauthn-json": "^2.1.1", - "@rails/ujs": "7.1.3-3", + "@rails/ujs": "7.1.3", "@reduxjs/toolkit": "^2.0.1", "@svgr/webpack": "^5.5.0", "arrow-key-navigation": "^1.2.0", diff --git a/yarn.lock b/yarn.lock index 6b1dd8d22d..698824cab4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2758,7 +2758,7 @@ __metadata: "@formatjs/intl-pluralrules": "npm:^5.2.2" "@gamestdio/websocket": "npm:^0.3.2" "@github/webauthn-json": "npm:^2.1.1" - "@rails/ujs": "npm:7.1.3-3" + "@rails/ujs": "npm:7.1.3" "@reduxjs/toolkit": "npm:^2.0.1" "@svgr/webpack": "npm:^5.5.0" "@testing-library/jest-dom": "npm:^6.0.0" @@ -3042,10 +3042,10 @@ __metadata: languageName: node linkType: hard -"@rails/ujs@npm:7.1.3-3": - version: 7.1.3-3 - resolution: "@rails/ujs@npm:7.1.3-3" - checksum: 10c0/9eee95372b72d8f704b67f14a3bf9f2681ab5b11c7b79919bfde3341f2970771876af5b40de5b3e4fca6a97c76a41046eff71d96490617c1fc80ef3ad8bbac47 +"@rails/ujs@npm:7.1.3": + version: 7.1.3 + resolution: "@rails/ujs@npm:7.1.3" + checksum: 10c0/68112d9add9dbc59b40c2ec1bc095a67445c57d20d0ab7d817ce3de0cd90374e2690af8ad54ce6ecc2d1c748b34c0c44d0fbd2f515ce2c443d7c5d23d00b9ce5 languageName: node linkType: hard From 9658d3e5804ab1e2180a70b6b19386592731fd78 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 20 May 2024 10:01:04 +0200 Subject: [PATCH 200/658] Use the job class as span name for Sidekiq root spans (#30353) --- config/initializers/opentelemetry.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/initializers/opentelemetry.rb b/config/initializers/opentelemetry.rb index 9af0ab89c8..cf9f0b96f3 100644 --- a/config/initializers/opentelemetry.rb +++ b/config/initializers/opentelemetry.rb @@ -51,6 +51,9 @@ if ENV.keys.any? { |name| name.match?(/OTEL_.*_ENDPOINT/) } use_rack_events: false, # instead of events, use middleware; allows for untraced_endpoints to ignore child spans untraced_endpoints: ['/health'], }, + 'OpenTelemetry::Instrumentation::Sidekiq' => { + span_naming: :job_class, # Use the job class as the span name, otherwise this is the queue name and not very helpful + }, }) prefix = ENV.fetch('OTEL_SERVICE_NAME_PREFIX', 'mastodon') From 70608f824e4bdd197d179c70efc82effcefc0c6b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 20 May 2024 04:03:39 -0400 Subject: [PATCH 201/658] Add coverage for `AdminMailer#auto_close_registrations` (#30349) --- spec/mailers/admin_mailer_spec.rb | 18 ++++++++++++++++++ spec/mailers/previews/admin_mailer_preview.rb | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/spec/mailers/admin_mailer_spec.rb b/spec/mailers/admin_mailer_spec.rb index 88ad7aa02b..cd1ab3311c 100644 --- a/spec/mailers/admin_mailer_spec.rb +++ b/spec/mailers/admin_mailer_spec.rb @@ -125,4 +125,22 @@ RSpec.describe AdminMailer do .and(have_header('X-Priority', '1')) end end + + describe '.auto_close_registrations' do + let(:recipient) { Fabricate(:account, username: 'Bob') } + let(:mail) { described_class.with(recipient: recipient).auto_close_registrations } + + before do + recipient.user.update(locale: :en) + end + + it 'renders the email' do + expect(mail) + .to be_present + .and(deliver_to(recipient.user_email)) + .and(deliver_from('notifications@localhost')) + .and(have_subject('Registrations for cb6e6126.ngrok.io have been automatically switched to requiring approval')) + .and(have_body_text('have been automatically switched')) + end + end end diff --git a/spec/mailers/previews/admin_mailer_preview.rb b/spec/mailers/previews/admin_mailer_preview.rb index 942d40d568..b8fb387acd 100644 --- a/spec/mailers/previews/admin_mailer_preview.rb +++ b/spec/mailers/previews/admin_mailer_preview.rb @@ -32,4 +32,9 @@ class AdminMailerPreview < ActionMailer::Preview def new_critical_software_updates AdminMailer.with(recipient: Account.first).new_critical_software_updates end + + # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/auto_close_registrations + def auto_close_registrations + AdminMailer.with(recipient: Account.first).auto_close_registrations + end end From def6b686ff3ea8e4e77075a812bd463a3bf325c3 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 20 May 2024 05:37:36 -0400 Subject: [PATCH 202/658] Fix `Rails/WhereRange` cop (#30343) --- app/lib/vacuum/imports_vacuum.rb | 4 ++-- app/lib/vacuum/statuses_vacuum.rb | 2 +- app/models/concerns/expireable.rb | 2 +- app/models/invite.rb | 2 +- app/policies/backup_policy.rb | 2 +- app/workers/scheduler/ip_cleanup_scheduler.rb | 10 +++++----- app/workers/scheduler/scheduled_statuses_scheduler.rb | 2 +- app/workers/scheduler/user_cleanup_scheduler.rb | 2 +- lib/mastodon/cli/preview_cards.rb | 2 +- .../accounts_statuses_cleanup_scheduler_spec.rb | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/lib/vacuum/imports_vacuum.rb b/app/lib/vacuum/imports_vacuum.rb index 8c8bb783ac..700bd81847 100644 --- a/app/lib/vacuum/imports_vacuum.rb +++ b/app/lib/vacuum/imports_vacuum.rb @@ -9,10 +9,10 @@ class Vacuum::ImportsVacuum private def clean_unconfirmed_imports! - BulkImport.state_unconfirmed.where('created_at <= ?', 10.minutes.ago).reorder(nil).in_batches.delete_all + BulkImport.state_unconfirmed.where(created_at: ..10.minutes.ago).reorder(nil).in_batches.delete_all end def clean_old_imports! - BulkImport.where('created_at <= ?', 1.week.ago).reorder(nil).in_batches.delete_all + BulkImport.where(created_at: ..1.week.ago).reorder(nil).in_batches.delete_all end end diff --git a/app/lib/vacuum/statuses_vacuum.rb b/app/lib/vacuum/statuses_vacuum.rb index ad1de07380..92d3ccf4f4 100644 --- a/app/lib/vacuum/statuses_vacuum.rb +++ b/app/lib/vacuum/statuses_vacuum.rb @@ -34,7 +34,7 @@ class Vacuum::StatusesVacuum def statuses_scope Status.unscoped.kept .joins(:account).merge(Account.remote) - .where('statuses.id < ?', retention_period_as_id) + .where(statuses: { id: ...retention_period_as_id }) end def retention_period_as_id diff --git a/app/models/concerns/expireable.rb b/app/models/concerns/expireable.rb index c64fc7d807..26740e8213 100644 --- a/app/models/concerns/expireable.rb +++ b/app/models/concerns/expireable.rb @@ -4,7 +4,7 @@ module Expireable extend ActiveSupport::Concern included do - scope :expired, -> { where.not(expires_at: nil).where('expires_at < ?', Time.now.utc) } + scope :expired, -> { where.not(expires_at: nil).where(expires_at: ...Time.now.utc) } def expires_in return @expires_in if defined?(@expires_in) diff --git a/app/models/invite.rb b/app/models/invite.rb index 2fe9f22fbe..ea095a3ac1 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -24,7 +24,7 @@ class Invite < ApplicationRecord belongs_to :user, inverse_of: :invites has_many :users, inverse_of: :invite, dependent: nil - scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) } + scope :available, -> { where(expires_at: nil).or(where(expires_at: Time.now.utc..)) } validates :comment, length: { maximum: COMMENT_SIZE_LIMIT } diff --git a/app/policies/backup_policy.rb b/app/policies/backup_policy.rb index 86b8efbe96..7a4c5b4347 100644 --- a/app/policies/backup_policy.rb +++ b/app/policies/backup_policy.rb @@ -4,6 +4,6 @@ class BackupPolicy < ApplicationPolicy MIN_AGE = 6.days def create? - user_signed_in? && current_user.backups.where('created_at >= ?', MIN_AGE.ago).count.zero? + user_signed_in? && current_user.backups.where(created_at: MIN_AGE.ago..).count.zero? end end diff --git a/app/workers/scheduler/ip_cleanup_scheduler.rb b/app/workers/scheduler/ip_cleanup_scheduler.rb index f78c0584d7..04fb0aaa33 100644 --- a/app/workers/scheduler/ip_cleanup_scheduler.rb +++ b/app/workers/scheduler/ip_cleanup_scheduler.rb @@ -16,11 +16,11 @@ class Scheduler::IpCleanupScheduler private def clean_ip_columns! - SessionActivation.where('updated_at < ?', SESSION_RETENTION_PERIOD.ago).in_batches.destroy_all - SessionActivation.where('updated_at < ?', IP_RETENTION_PERIOD.ago).in_batches.update_all(ip: nil) - User.where('current_sign_in_at < ?', IP_RETENTION_PERIOD.ago).in_batches.update_all(sign_up_ip: nil) - LoginActivity.where('created_at < ?', IP_RETENTION_PERIOD.ago).in_batches.destroy_all - Doorkeeper::AccessToken.where('last_used_at < ?', IP_RETENTION_PERIOD.ago).in_batches.update_all(last_used_ip: nil) + SessionActivation.where(updated_at: ...SESSION_RETENTION_PERIOD.ago).in_batches.destroy_all + SessionActivation.where(updated_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(ip: nil) + User.where(current_sign_in_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(sign_up_ip: nil) + LoginActivity.where(created_at: ...IP_RETENTION_PERIOD.ago).in_batches.destroy_all + Doorkeeper::AccessToken.where(last_used_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(last_used_ip: nil) end def clean_expired_ip_blocks! diff --git a/app/workers/scheduler/scheduled_statuses_scheduler.rb b/app/workers/scheduler/scheduled_statuses_scheduler.rb index fe60d5524e..4e251780de 100644 --- a/app/workers/scheduler/scheduled_statuses_scheduler.rb +++ b/app/workers/scheduler/scheduled_statuses_scheduler.rb @@ -20,7 +20,7 @@ class Scheduler::ScheduledStatusesScheduler end def due_statuses - ScheduledStatus.where('scheduled_at <= ?', Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET) + ScheduledStatus.where(scheduled_at: ..Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET) end def publish_scheduled_announcements! diff --git a/app/workers/scheduler/user_cleanup_scheduler.rb b/app/workers/scheduler/user_cleanup_scheduler.rb index 63ea876e50..74abc23701 100644 --- a/app/workers/scheduler/user_cleanup_scheduler.rb +++ b/app/workers/scheduler/user_cleanup_scheduler.rb @@ -25,7 +25,7 @@ class Scheduler::UserCleanupScheduler end def clean_discarded_statuses! - Status.unscoped.discarded.where('deleted_at <= ?', DISCARDED_STATUSES_MAX_AGE_DAYS.days.ago).find_in_batches do |statuses| + Status.unscoped.discarded.where(deleted_at: ..DISCARDED_STATUSES_MAX_AGE_DAYS.days.ago).find_in_batches do |statuses| RemovalWorker.push_bulk(statuses) do |status| [status.id, { 'immediate' => true, 'skip_streaming' => true }] end diff --git a/lib/mastodon/cli/preview_cards.rb b/lib/mastodon/cli/preview_cards.rb index 9b20a0cbb8..c0e207ad59 100644 --- a/lib/mastodon/cli/preview_cards.rb +++ b/lib/mastodon/cli/preview_cards.rb @@ -29,7 +29,7 @@ module Mastodon::CLI link = options[:link] ? 'link-type ' : '' scope = PreviewCard.cached scope = scope.where(type: :link) if options[:link] - scope = scope.where('updated_at < ?', time_ago) + scope = scope.where(updated_at: ...time_ago) processed, aggregate = parallelize_with_progress(scope) do |preview_card| next if preview_card.image.blank? diff --git a/spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb b/spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb index 4d9185093a..08ebf82785 100644 --- a/spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb +++ b/spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb @@ -163,7 +163,7 @@ describe Scheduler::AccountsStatusesCleanupScheduler do def cleanable_statuses_count Status .where(account_id: [account_alice, account_chris, account_erin]) # Accounts with enabled policies - .where('created_at < ?', 2.weeks.ago) # Policy defaults is 2.weeks + .where(created_at: ...2.weeks.ago) # Policy defaults is 2.weeks .count end end From de4815afda0809bf999519aabda1cd14c67278da Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 20 May 2024 12:06:51 +0200 Subject: [PATCH 203/658] Add more tests for self-destruct mode (#30374) --- spec/helpers/self_destruct_helper_spec.rb | 70 +++++++++++++++++ spec/requests/self_destruct_spec.rb | 92 +++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 spec/helpers/self_destruct_helper_spec.rb create mode 100644 spec/requests/self_destruct_spec.rb diff --git a/spec/helpers/self_destruct_helper_spec.rb b/spec/helpers/self_destruct_helper_spec.rb new file mode 100644 index 0000000000..09d7347eee --- /dev/null +++ b/spec/helpers/self_destruct_helper_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe SelfDestructHelper do + describe 'self_destruct?' do + context 'when SELF_DESTRUCT is unset' do + it 'returns false' do + expect(helper.self_destruct?).to be false + end + end + + context 'when SELF_DESTRUCT is set to an invalid value' do + around do |example| + ClimateControl.modify SELF_DESTRUCT: 'true' do + example.run + end + end + + it 'returns false' do + expect(helper.self_destruct?).to be false + end + end + + context 'when SELF_DESTRUCT is set to value signed for the wrong purpose' do + around do |example| + ClimateControl.modify( + SELF_DESTRUCT: Rails.application.message_verifier('foo').generate('example.com'), + LOCAL_DOMAIN: 'example.com' + ) do + example.run + end + end + + it 'returns false' do + expect(helper.self_destruct?).to be false + end + end + + context 'when SELF_DESTRUCT is set to value signed for the wrong domain' do + around do |example| + ClimateControl.modify( + SELF_DESTRUCT: Rails.application.message_verifier('self-destruct').generate('foo.com'), + LOCAL_DOMAIN: 'example.com' + ) do + example.run + end + end + + it 'returns false' do + expect(helper.self_destruct?).to be false + end + end + + context 'when SELF_DESTRUCT is set to a correctly-signed value' do + around do |example| + ClimateControl.modify( + SELF_DESTRUCT: Rails.application.message_verifier('self-destruct').generate('example.com'), + LOCAL_DOMAIN: 'example.com' + ) do + example.run + end + end + + it 'returns true' do + expect(helper.self_destruct?).to be true + end + end + end +end diff --git a/spec/requests/self_destruct_spec.rb b/spec/requests/self_destruct_spec.rb new file mode 100644 index 0000000000..f71a2325e2 --- /dev/null +++ b/spec/requests/self_destruct_spec.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Self-destruct mode' do + before do + allow(SelfDestructHelper).to receive(:self_destruct?).and_return(true) + end + + shared_examples 'generic logged out request' do |path| + it 'returns 410 gone and mentions self-destruct' do + get path, headers: { 'Accept' => 'text/html' } + + expect(response).to have_http_status(410) + expect(response.body).to include(I18n.t('self_destruct.title')) + end + end + + shared_examples 'accessible logged-in endpoint' do |path| + it 'returns 200 ok' do + get path + + expect(response).to have_http_status(200) + end + end + + shared_examples 'ActivityPub request' do |path| + context 'without signature' do + it 'returns 410 gone' do + get path, headers: { + 'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + } + + expect(response).to have_http_status(410) + end + end + + context 'with invalid signature' do + it 'returns 410 gone' do + get path, headers: { + 'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + 'Signature' => 'keyId="https://remote.domain/users/bob#main-key",algorithm="rsa-sha256",headers="date host (request-target)",signature="bar"', + } + + expect(response).to have_http_status(410) + end + end + end + + context 'when requesting various unavailable endpoints' do + it_behaves_like 'generic logged out request', '/' + it_behaves_like 'generic logged out request', '/about' + it_behaves_like 'generic logged out request', '/public' + end + + context 'when requesting a suspended account' do + let(:suspended) { Fabricate(:account, username: 'suspended') } + + before do + suspended.suspend! + end + + it_behaves_like 'generic logged out request', '/@suspended' + it_behaves_like 'ActivityPub request', '/users/suspended' + it_behaves_like 'ActivityPub request', '/users/suspended/followers' + it_behaves_like 'ActivityPub request', '/users/suspended/outbox' + end + + context 'when requesting a non-suspended account' do + before do + Fabricate(:account, username: 'bob') + end + + it_behaves_like 'generic logged out request', '/@bob' + it_behaves_like 'ActivityPub request', '/users/bob' + it_behaves_like 'ActivityPub request', '/users/bob/followers' + it_behaves_like 'ActivityPub request', '/users/bob/outbox' + end + + context 'when accessing still-enabled endpoints when logged in' do + let(:user) { Fabricate(:user) } + + before do + sign_in(user) + end + + it_behaves_like 'accessible logged-in endpoint', '/auth/edit' + it_behaves_like 'accessible logged-in endpoint', '/settings/export' + it_behaves_like 'accessible logged-in endpoint', '/settings/login_activities' + it_behaves_like 'accessible logged-in endpoint', '/settings/exports/follows.csv' + end +end From ca5955ed76ebec90fa87983017904a7b2b0c56a3 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Sun, 19 May 2024 19:07:32 +0200 Subject: [PATCH 204/658] [Glitch] Use a modern React context for identity in the app Port a178ba7cd5fa10b018ecaf3c8e3dd5f298a08818 to glitch-soc Signed-off-by: Claire --- .../glitch/components/column_header.jsx | 12 ++- .../flavours/glitch/components/poll.jsx | 11 +-- .../glitch/components/status_action_bar.jsx | 17 ++--- .../glitch/components/status_content.jsx | 11 +-- .../flavours/glitch/containers/mastodon.jsx | 52 ++++--------- .../features/account/components/header.jsx | 10 +-- .../features/community_timeline/index.jsx | 13 ++-- .../features/compose/components/search.jsx | 13 ++-- .../glitch/features/explore/index.jsx | 11 +-- .../glitch/features/firehose/index.jsx | 12 +-- .../glitch/features/getting_started/index.jsx | 13 ++-- .../features/getting_started_misc/index.jsx | 11 +-- .../features/hashtag_timeline/index.jsx | 15 ++-- .../glitch/features/home_timeline/index.jsx | 11 +-- .../components/column_settings.jsx | 15 ++-- .../glitch/features/notifications/index.jsx | 11 +-- .../picture_in_picture/components/footer.jsx | 15 ++-- .../glitch/features/public_timeline/index.jsx | 13 ++-- .../features/status/components/action_bar.jsx | 11 +-- .../flavours/glitch/features/status/index.jsx | 15 ++-- .../features/ui/components/compose_panel.jsx | 11 +-- .../glitch/features/ui/components/header.jsx | 11 +-- .../features/ui/components/link_footer.jsx | 11 +-- .../ui/components/navigation_panel.jsx | 11 +-- .../flavours/glitch/features/ui/index.jsx | 25 +++---- .../flavours/glitch/identity_context.tsx | 74 +++++++++++++++++++ .../flavours/glitch/initial_state.js | 10 +++ 27 files changed, 215 insertions(+), 230 deletions(-) create mode 100644 app/javascript/flavours/glitch/identity_context.tsx diff --git a/app/javascript/flavours/glitch/components/column_header.jsx b/app/javascript/flavours/glitch/components/column_header.jsx index 0177812480..210ec396fa 100644 --- a/app/javascript/flavours/glitch/components/column_header.jsx +++ b/app/javascript/flavours/glitch/components/column_header.jsx @@ -14,8 +14,10 @@ import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import SettingsIcon from '@/material-icons/400-24px/settings.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; import { ButtonInTabsBar } from 'flavours/glitch/features/ui/util/columns_context'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; + import { useAppHistory } from './router'; const messages = defineMessages({ @@ -51,12 +53,8 @@ BackButton.propTypes = { }; class ColumnHeader extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, title: PropTypes.node, icon: PropTypes.string, @@ -171,7 +169,7 @@ class ColumnHeader extends PureComponent { ); } - if (this.context.identity.signedIn && (children || (multiColumn && this.props.onPin))) { + if (this.props.identity.signedIn && (children || (multiColumn && this.props.onPin))) { collapseButton = ( } + {!showResults && } {!showResults && <> · } {showResults && !this.props.disabled && <> · } {votesCount} @@ -247,4 +244,4 @@ class Poll extends ImmutablePureComponent { } -export default injectIntl(Poll); +export default injectIntl(withIdentity(Poll)); diff --git a/app/javascript/flavours/glitch/components/status_action_bar.jsx b/app/javascript/flavours/glitch/components/status_action_bar.jsx index f27719a6b9..3dfe403987 100644 --- a/app/javascript/flavours/glitch/components/status_action_bar.jsx +++ b/app/javascript/flavours/glitch/components/status_action_bar.jsx @@ -21,6 +21,7 @@ import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react'; import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg'; import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg'; import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions'; import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; @@ -67,12 +68,8 @@ const messages = defineMessages({ }); class StatusActionBar extends ImmutablePureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, status: ImmutablePropTypes.map.isRequired, onReply: PropTypes.func, onFavourite: PropTypes.func, @@ -108,7 +105,7 @@ class StatusActionBar extends ImmutablePureComponent { ]; handleReplyClick = () => { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { this.props.onReply(this.props.status, this.props.history); @@ -124,7 +121,7 @@ class StatusActionBar extends ImmutablePureComponent { }; handleFavouriteClick = (e) => { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { this.props.onFavourite(this.props.status, e); @@ -134,7 +131,7 @@ class StatusActionBar extends ImmutablePureComponent { }; handleReblogClick = e => { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { this.props.onReblog(this.props.status, e); @@ -210,7 +207,7 @@ class StatusActionBar extends ImmutablePureComponent { render () { const { status, intl, withDismiss, withCounters, showReplyCount, scrollKey } = this.props; - const { permissions, signedIn } = this.context.identity; + const { permissions, signedIn } = this.props.identity; const mutingConversation = status.get('muted'); const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); @@ -359,4 +356,4 @@ class StatusActionBar extends ImmutablePureComponent { } -export default withRouter(injectIntl(StatusActionBar)); +export default withRouter(withIdentity(injectIntl(StatusActionBar))); diff --git a/app/javascript/flavours/glitch/components/status_content.jsx b/app/javascript/flavours/glitch/components/status_content.jsx index f5d5ccc70a..24da69cdf2 100644 --- a/app/javascript/flavours/glitch/components/status_content.jsx +++ b/app/javascript/flavours/glitch/components/status_content.jsx @@ -15,6 +15,7 @@ import LinkIcon from '@/material-icons/400-24px/link.svg?react'; import MovieIcon from '@/material-icons/400-24px/movie.svg?react'; import MusicNoteIcon from '@/material-icons/400-24px/music_note.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { autoPlayGif, languages as preloadedLanguages } from 'flavours/glitch/initial_state'; import { decode as decodeIDNA } from 'flavours/glitch/utils/idna'; @@ -126,12 +127,8 @@ const mapStateToProps = state => ({ }); class StatusContent extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, status: ImmutablePropTypes.map.isRequired, statusContent: PropTypes.string, expanded: PropTypes.bool, @@ -349,7 +346,7 @@ class StatusContent extends PureComponent { const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden; const contentLocale = intl.locale.replace(/[_-].*/, ''); const targetLanguages = this.props.languages?.get(status.get('language') || 'und'); - const renderTranslate = this.props.onTranslate && this.context.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale); + const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale); const content = { __html: statusContent ?? getStatusContent(status) }; const spoilerContent = { __html: status.getIn(['translation', 'spoilerHtml']) || status.get('spoilerHtml') }; @@ -503,4 +500,4 @@ class StatusContent extends PureComponent { } -export default withRouter(connect(mapStateToProps)(injectIntl(StatusContent))); +export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusContent)))); diff --git a/app/javascript/flavours/glitch/containers/mastodon.jsx b/app/javascript/flavours/glitch/containers/mastodon.jsx index 1704336f2c..c0f63b95b4 100644 --- a/app/javascript/flavours/glitch/containers/mastodon.jsx +++ b/app/javascript/flavours/glitch/containers/mastodon.jsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import { PureComponent } from 'react'; import { Helmet } from 'react-helmet'; @@ -15,6 +14,7 @@ import { connectUserStream } from 'flavours/glitch/actions/streaming'; import ErrorBoundary from 'flavours/glitch/components/error_boundary'; import { Router } from 'flavours/glitch/components/router'; import UI from 'flavours/glitch/features/ui'; +import { IdentityContext, createIdentityContext } from 'flavours/glitch/identity_context'; import initialState, { title as siteTitle } from 'flavours/glitch/initial_state'; import { IntlProvider } from 'flavours/glitch/locales'; import { store } from 'flavours/glitch/store'; @@ -33,33 +33,9 @@ if (initialState.meta.me) { store.dispatch(fetchCustomEmojis()); } -const createIdentityContext = state => ({ - signedIn: !!state.meta.me, - accountId: state.meta.me, - disabledAccountId: state.meta.disabled_account_id, - accessToken: state.meta.access_token, - permissions: state.role ? state.role.permissions : 0, -}); - export default class Mastodon extends PureComponent { - - static childContextTypes = { - identity: PropTypes.shape({ - signedIn: PropTypes.bool.isRequired, - accountId: PropTypes.string, - disabledAccountId: PropTypes.string, - accessToken: PropTypes.string, - }).isRequired, - }; - identity = createIdentityContext(initialState); - getChildContext() { - return { - identity: this.identity, - }; - } - componentDidMount() { if (this.identity.signedIn) { this.disconnect = store.dispatch(connectUserStream()); @@ -79,19 +55,21 @@ export default class Mastodon extends PureComponent { render () { return ( - - - - - - - - + + + + + + + + + - - - - + + + + + ); } diff --git a/app/javascript/flavours/glitch/features/account/components/header.jsx b/app/javascript/flavours/glitch/features/account/components/header.jsx index e311936af9..62c8c84c66 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.jsx +++ b/app/javascript/flavours/glitch/features/account/components/header.jsx @@ -23,6 +23,7 @@ import { Icon } from 'flavours/glitch/components/icon'; import { IconButton } from 'flavours/glitch/components/icon_button'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { autoPlayGif, me, domain as localDomain } from 'flavours/glitch/initial_state'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions'; import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/utils/backend_links'; @@ -94,6 +95,7 @@ const dateFormatOptions = { class Header extends ImmutablePureComponent { static propTypes = { + identity: identityContextPropShape, account: ImmutablePropTypes.record, identity_props: ImmutablePropTypes.list, onFollow: PropTypes.func.isRequired, @@ -117,10 +119,6 @@ class Header extends ImmutablePureComponent { ...WithRouterPropTypes, }; - static contextTypes = { - identity: PropTypes.object, - }; - openEditProfile = () => { window.open(profileLink, '_blank'); }; @@ -170,7 +168,7 @@ class Header extends ImmutablePureComponent { render () { const { account, hidden, intl } = this.props; - const { signedIn, permissions } = this.context.identity; + const { signedIn, permissions } = this.props.identity; if (!account) { return null; @@ -414,4 +412,4 @@ class Header extends ImmutablePureComponent { } -export default withRouter(injectIntl(Header)); +export default withRouter(withIdentity(injectIntl(Header))); diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.jsx b/app/javascript/flavours/glitch/features/community_timeline/index.jsx index 7be2196511..9f306923e3 100644 --- a/app/javascript/flavours/glitch/features/community_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/community_timeline/index.jsx @@ -9,6 +9,7 @@ import { connect } from 'react-redux'; import PeopleIcon from '@/material-icons/400-24px/group.svg?react'; import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { domain } from 'flavours/glitch/initial_state'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; @@ -40,16 +41,12 @@ const mapStateToProps = (state, { columnId }) => { }; class CommunityTimeline extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static defaultProps = { onlyMedia: false, }; static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, columnId: PropTypes.string, intl: PropTypes.object.isRequired, @@ -80,7 +77,7 @@ class CommunityTimeline extends PureComponent { componentDidMount () { const { dispatch, onlyMedia } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; dispatch(expandCommunityTimeline({ onlyMedia })); @@ -90,7 +87,7 @@ class CommunityTimeline extends PureComponent { } componentDidUpdate (prevProps) { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (prevProps.onlyMedia !== this.props.onlyMedia) { const { dispatch, onlyMedia } = this.props; @@ -165,4 +162,4 @@ class CommunityTimeline extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(CommunityTimeline)); +export default withIdentity(connect(mapStateToProps)(injectIntl(CommunityTimeline))); diff --git a/app/javascript/flavours/glitch/features/compose/components/search.jsx b/app/javascript/flavours/glitch/features/compose/components/search.jsx index 4b64038f57..f5a51334af 100644 --- a/app/javascript/flavours/glitch/features/compose/components/search.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/search.jsx @@ -12,6 +12,7 @@ import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import { Icon } from 'flavours/glitch/components/icon'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { domain, searchEnabled } from 'flavours/glitch/initial_state'; import { HASHTAG_REGEX } from 'flavours/glitch/utils/hashtags'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; @@ -33,12 +34,8 @@ const labelForRecentSearch = search => { }; class Search extends PureComponent { - - static contextTypes = { - identity: PropTypes.object.isRequired, - }; - static propTypes = { + identity: identityContextPropShape, value: PropTypes.string.isRequired, recent: ImmutablePropTypes.orderedSet, submitted: PropTypes.bool, @@ -276,7 +273,7 @@ class Search extends PureComponent { } _calculateOptions (value) { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const trimmedValue = value.trim(); const options = []; @@ -318,7 +315,7 @@ class Search extends PureComponent { render () { const { intl, value, submitted, recent } = this.props; const { expanded, options, selectedOption } = this.state; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const hasValue = value.length > 0 || submitted; @@ -402,4 +399,4 @@ class Search extends PureComponent { } -export default withRouter(injectIntl(Search)); +export default withRouter(withIdentity(injectIntl(Search))); diff --git a/app/javascript/flavours/glitch/features/explore/index.jsx b/app/javascript/flavours/glitch/features/explore/index.jsx index cca9cada47..8137e75ea4 100644 --- a/app/javascript/flavours/glitch/features/explore/index.jsx +++ b/app/javascript/flavours/glitch/features/explore/index.jsx @@ -13,6 +13,7 @@ import SearchIcon from '@/material-icons/400-24px/search.svg?react'; import Column from 'flavours/glitch/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; import Search from 'flavours/glitch/features/compose/containers/search_container'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { trendsEnabled } from 'flavours/glitch/initial_state'; import Links from './links'; @@ -32,12 +33,8 @@ const mapStateToProps = state => ({ }); class Explore extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, multiColumn: PropTypes.bool, isSearching: PropTypes.bool, @@ -53,7 +50,7 @@ class Explore extends PureComponent { render() { const { intl, multiColumn, isSearching } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; return ( @@ -114,4 +111,4 @@ class Explore extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(Explore)); +export default withIdentity(connect(mapStateToProps)(injectIntl(Explore))); diff --git a/app/javascript/flavours/glitch/features/firehose/index.jsx b/app/javascript/flavours/glitch/features/firehose/index.jsx index dc6a38ae2e..2a6d790d52 100644 --- a/app/javascript/flavours/glitch/features/firehose/index.jsx +++ b/app/javascript/flavours/glitch/features/firehose/index.jsx @@ -6,6 +6,7 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; import { Helmet } from 'react-helmet'; import { NavLink } from 'react-router-dom'; +import { useIdentity } from '@/flavours/glitch/identity_context'; import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { addColumn } from 'flavours/glitch/actions/columns'; import { changeSetting } from 'flavours/glitch/actions/settings'; @@ -13,7 +14,7 @@ import { connectPublicStream, connectCommunityStream } from 'flavours/glitch/act import { expandPublicTimeline, expandCommunityTimeline } from 'flavours/glitch/actions/timelines'; import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner'; import SettingText from 'flavours/glitch/components/setting_text'; -import initialState, { domain } from 'flavours/glitch/initial_state'; +import { domain } from 'flavours/glitch/initial_state'; import { useAppDispatch, useAppSelector } from 'flavours/glitch/store'; import Column from '../../components/column'; @@ -26,15 +27,6 @@ const messages = defineMessages({ filter_regex: { id: 'home.column_settings.filter_regex', defaultMessage: 'Filter out by regular expressions' }, }); -// TODO: use a proper React context later on -const useIdentity = () => ({ - signedIn: !!initialState.meta.me, - accountId: initialState.meta.me, - disabledAccountId: initialState.meta.disabled_account_id, - accessToken: initialState.meta.access_token, - permissions: initialState.role ? initialState.role.permissions : 0, -}); - const ColumnSettings = () => { const intl = useIntl(); const dispatch = useAppDispatch(); diff --git a/app/javascript/flavours/glitch/features/getting_started/index.jsx b/app/javascript/flavours/glitch/features/getting_started/index.jsx index 145cb09a30..2d13d3d584 100644 --- a/app/javascript/flavours/glitch/features/getting_started/index.jsx +++ b/app/javascript/flavours/glitch/features/getting_started/index.jsx @@ -28,6 +28,7 @@ import { fetchLists } from 'flavours/glitch/actions/lists'; import { openModal } from 'flavours/glitch/actions/modal'; import Column from 'flavours/glitch/features/ui/components/column'; import LinkFooter from 'flavours/glitch/features/ui/components/link_footer'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { preferencesLink } from 'flavours/glitch/utils/backend_links'; @@ -99,12 +100,8 @@ const badgeDisplay = (number, limit) => { }; class GettingStarted extends ImmutablePureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, myAccount: ImmutablePropTypes.record, columns: ImmutablePropTypes.list, @@ -123,7 +120,7 @@ class GettingStarted extends ImmutablePureComponent { componentDidMount () { const { fetchFollowRequests } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (!signedIn) { return; @@ -134,7 +131,7 @@ class GettingStarted extends ImmutablePureComponent { render () { const { intl, myAccount, columns, multiColumn, unreadFollowRequests, unreadNotifications, lists, openSettings } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const navItems = []; let listItems = []; @@ -219,4 +216,4 @@ class GettingStarted extends ImmutablePureComponent { } -export default connect(makeMapStateToProps, mapDispatchToProps)(injectIntl(GettingStarted)); +export default withIdentity(connect(makeMapStateToProps, mapDispatchToProps)(injectIntl(GettingStarted))); diff --git a/app/javascript/flavours/glitch/features/getting_started_misc/index.jsx b/app/javascript/flavours/glitch/features/getting_started_misc/index.jsx index 7c4979bd63..4a0dbb4a1c 100644 --- a/app/javascript/flavours/glitch/features/getting_started_misc/index.jsx +++ b/app/javascript/flavours/glitch/features/getting_started_misc/index.jsx @@ -16,7 +16,7 @@ import { openModal } from 'flavours/glitch/actions/modal'; import Column from 'flavours/glitch/features/ui/components/column'; import ColumnLink from 'flavours/glitch/features/ui/components/column_link'; import ColumnSubheading from 'flavours/glitch/features/ui/components/column_subheading'; - +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; const messages = defineMessages({ heading: { id: 'column.heading', defaultMessage: 'Misc' }, @@ -32,11 +32,8 @@ const messages = defineMessages({ class GettingStartedMisc extends ImmutablePureComponent { - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, }; @@ -49,7 +46,7 @@ class GettingStartedMisc extends ImmutablePureComponent { render () { const { intl } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; return ( @@ -69,4 +66,4 @@ class GettingStartedMisc extends ImmutablePureComponent { } -export default connect()(injectIntl(GettingStartedMisc)); +export default connect()(withIdentity(injectIntl(GettingStartedMisc))); diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.jsx b/app/javascript/flavours/glitch/features/hashtag_timeline/index.jsx index c2a7574307..c33c458c27 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.jsx @@ -17,6 +17,7 @@ import { fetchHashtag, followHashtag, unfollowHashtag } from 'flavours/glitch/ac import { expandHashtagTimeline, clearTimeline } from 'flavours/glitch/actions/timelines'; import Column from 'flavours/glitch/components/column'; import ColumnHeader from 'flavours/glitch/components/column_header'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import StatusListContainer from '../ui/containers/status_list_container'; @@ -29,14 +30,10 @@ const mapStateToProps = (state, props) => ({ }); class HashtagTimeline extends PureComponent { - disconnects = []; - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, params: PropTypes.object.isRequired, columnId: PropTypes.string, dispatch: PropTypes.func.isRequired, @@ -94,7 +91,7 @@ class HashtagTimeline extends PureComponent { }; _subscribe (dispatch, id, tags = {}, local) { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (!signedIn) { return; @@ -168,7 +165,7 @@ class HashtagTimeline extends PureComponent { handleFollow = () => { const { dispatch, params, tag } = this.props; const { id } = params; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (!signedIn) { return; @@ -185,7 +182,7 @@ class HashtagTimeline extends PureComponent { const { hasUnread, columnId, multiColumn, tag } = this.props; const { id, local } = this.props.params; const pinned = !!columnId; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; return ( @@ -225,4 +222,4 @@ class HashtagTimeline extends PureComponent { } -export default connect(mapStateToProps)(HashtagTimeline); +export default connect(mapStateToProps)(withIdentity(HashtagTimeline)); diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.jsx b/app/javascript/flavours/glitch/features/home_timeline/index.jsx index a2683f587f..3220f777e1 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/home_timeline/index.jsx @@ -14,6 +14,7 @@ import { fetchAnnouncements, toggleShowAnnouncements } from 'flavours/glitch/act import { IconWithBadge } from 'flavours/glitch/components/icon_with_badge'; import { NotSignedInIndicator } from 'flavours/glitch/components/not_signed_in_indicator'; import AnnouncementsContainer from 'flavours/glitch/features/getting_started/containers/announcements_container'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { criticalUpdatesPending } from 'flavours/glitch/initial_state'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; @@ -41,12 +42,8 @@ const mapStateToProps = state => ({ }); class HomeTimeline extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, hasUnread: PropTypes.bool, @@ -128,7 +125,7 @@ class HomeTimeline extends PureComponent { render () { const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props; const pinned = !!columnId; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const banners = []; let announcementsButton; @@ -192,4 +189,4 @@ class HomeTimeline extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(HomeTimeline)); +export default connect(mapStateToProps)(withIdentity(injectIntl(HomeTimeline))); diff --git a/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx b/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx index 3f02df1881..ee78466b90 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx @@ -5,6 +5,7 @@ import { FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'flavours/glitch/permissions'; import { CheckboxWithLabel } from './checkbox_with_label'; @@ -13,13 +14,9 @@ import GrantPermissionButton from './grant_permission_button'; import PillBarButton from './pill_bar_button'; import SettingToggle from './setting_toggle'; -export default class ColumnSettings extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - +class ColumnSettings extends PureComponent { static propTypes = { + identity: identityContextPropShape, settings: ImmutablePropTypes.map.isRequired, pushSettings: ImmutablePropTypes.map.isRequired, onChange: PropTypes.func.isRequired, @@ -216,7 +213,7 @@ export default class ColumnSettings extends PureComponent {
- {((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && ( + {((this.props.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && (

@@ -229,7 +226,7 @@ export default class ColumnSettings extends PureComponent {
)} - {((this.context.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && ( + {((this.props.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && (

@@ -246,3 +243,5 @@ export default class ColumnSettings extends PureComponent { } } + +export default withIdentity(ColumnSettings); diff --git a/app/javascript/flavours/glitch/features/notifications/index.jsx b/app/javascript/flavours/glitch/features/notifications/index.jsx index e84ef70b05..b4f1bf5dfe 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.jsx +++ b/app/javascript/flavours/glitch/features/notifications/index.jsx @@ -19,6 +19,7 @@ import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg? import { compareId } from 'flavours/glitch/compare_id'; import { Icon } from 'flavours/glitch/components/icon'; import { NotSignedInIndicator } from 'flavours/glitch/components/not_signed_in_indicator'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { submitMarkers } from '../../actions/markers'; @@ -93,12 +94,8 @@ const mapDispatchToProps = dispatch => ({ }); class Notifications extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, columnId: PropTypes.string, notifications: ImmutablePropTypes.list.isRequired, showFilterBar: PropTypes.bool.isRequired, @@ -225,7 +222,7 @@ class Notifications extends PureComponent { const { animatingNCD } = this.state; const pinned = !!columnId; const emptyMessage = ; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; let scrollableContent = null; @@ -373,4 +370,4 @@ class Notifications extends PureComponent { } -export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(Notifications)); +export default connect(mapStateToProps, mapDispatchToProps)(withIdentity(injectIntl(Notifications))); diff --git a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx index e21ee2d3d3..0b6b91fe91 100644 --- a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx @@ -18,6 +18,7 @@ import { replyCompose } from 'flavours/glitch/actions/compose'; import { reblog, favourite, unreblog, unfavourite } from 'flavours/glitch/actions/interactions'; import { openModal } from 'flavours/glitch/actions/modal'; import { IconButton } from 'flavours/glitch/components/icon_button'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { me, boostModal } from 'flavours/glitch/initial_state'; import { makeGetStatus } from 'flavours/glitch/selectors'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; @@ -48,12 +49,8 @@ const makeMapStateToProps = () => { }; class Footer extends ImmutablePureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, statusId: PropTypes.string.isRequired, status: ImmutablePropTypes.map.isRequired, intl: PropTypes.object.isRequired, @@ -77,7 +74,7 @@ class Footer extends ImmutablePureComponent { handleReplyClick = () => { const { dispatch, askReplyConfirmation, status, intl } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (askReplyConfirmation) { @@ -106,7 +103,7 @@ class Footer extends ImmutablePureComponent { handleFavouriteClick = () => { const { dispatch, status } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (status.get('favourited')) { @@ -133,7 +130,7 @@ class Footer extends ImmutablePureComponent { handleReblogClick = e => { const { dispatch, status } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (status.get('reblogged')) { @@ -236,4 +233,4 @@ class Footer extends ImmutablePureComponent { } -export default connect(makeMapStateToProps)(withRouter(injectIntl(Footer))); +export default connect(makeMapStateToProps)(withIdentity(withRouter(injectIntl(Footer)))); diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.jsx b/app/javascript/flavours/glitch/features/public_timeline/index.jsx index 8b9503928b..1f255a468d 100644 --- a/app/javascript/flavours/glitch/features/public_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/public_timeline/index.jsx @@ -9,6 +9,7 @@ import { connect } from 'react-redux'; import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { domain } from 'flavours/glitch/initial_state'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; @@ -44,16 +45,12 @@ const mapStateToProps = (state, { columnId }) => { }; class PublicTimeline extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static defaultProps = { onlyMedia: false, }; static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, columnId: PropTypes.string, @@ -86,7 +83,7 @@ class PublicTimeline extends PureComponent { componentDidMount () { const { dispatch, onlyMedia, onlyRemote, allowLocalOnly } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; dispatch(expandPublicTimeline({ onlyMedia, onlyRemote, allowLocalOnly })); if (signedIn) { @@ -95,7 +92,7 @@ class PublicTimeline extends PureComponent { } componentDidUpdate (prevProps) { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.onlyRemote !== this.props.onlyRemote || prevProps.allowLocalOnly !== this.props.allowLocalOnly) { const { dispatch, onlyMedia, onlyRemote, allowLocalOnly } = this.props; @@ -170,4 +167,4 @@ class PublicTimeline extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(PublicTimeline)); +export default connect(mapStateToProps)(withIdentity(injectIntl(PublicTimeline))); diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.jsx b/app/javascript/flavours/glitch/features/status/components/action_bar.jsx index ab00091200..808712b021 100644 --- a/app/javascript/flavours/glitch/features/status/components/action_bar.jsx +++ b/app/javascript/flavours/glitch/features/status/components/action_bar.jsx @@ -20,6 +20,7 @@ import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react'; import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react'; import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react'; import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions'; import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; @@ -59,12 +60,8 @@ const messages = defineMessages({ }); class ActionBar extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, status: ImmutablePropTypes.map.isRequired, onReply: PropTypes.func.isRequired, onReblog: PropTypes.func.isRequired, @@ -157,7 +154,7 @@ class ActionBar extends PureComponent { render () { const { status, intl } = this.props; - const { signedIn, permissions } = this.context.identity; + const { signedIn, permissions } = this.props.identity; const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility')); @@ -265,4 +262,4 @@ class ActionBar extends PureComponent { } -export default withRouter(injectIntl(ActionBar)); +export default withRouter(withIdentity(injectIntl(ActionBar))); diff --git a/app/javascript/flavours/glitch/features/status/index.jsx b/app/javascript/flavours/glitch/features/status/index.jsx index 6274bf672c..2656f8afdd 100644 --- a/app/javascript/flavours/glitch/features/status/index.jsx +++ b/app/javascript/flavours/glitch/features/status/index.jsx @@ -21,6 +21,7 @@ import { Icon } from 'flavours/glitch/components/icon'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import ScrollContainer from 'flavours/glitch/containers/scroll_container'; import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; @@ -185,12 +186,8 @@ const titleFromStatus = (intl, status) => { }; class Status extends ImmutablePureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, params: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, status: ImmutablePropTypes.map, @@ -277,7 +274,7 @@ class Status extends ImmutablePureComponent { handleFavouriteClick = (status, e) => { const { dispatch } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (status.get('favourited')) { @@ -317,7 +314,7 @@ class Status extends ImmutablePureComponent { handleReplyClick = (status) => { const { askReplyConfirmation, dispatch, intl } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (askReplyConfirmation) { @@ -357,7 +354,7 @@ class Status extends ImmutablePureComponent { handleReblogClick = (status, e) => { const { settings, dispatch } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; if (signedIn) { if (settings.get('confirm_boost_missing_media_description') && status.get('media_attachments').some(item => !item.get('description')) && !status.get('reblogged')) { @@ -792,4 +789,4 @@ class Status extends ImmutablePureComponent { } -export default withRouter(injectIntl(connect(makeMapStateToProps)(Status))); +export default withRouter(injectIntl(connect(makeMapStateToProps)(withIdentity(Status)))); diff --git a/app/javascript/flavours/glitch/features/ui/components/compose_panel.jsx b/app/javascript/flavours/glitch/features/ui/components/compose_panel.jsx index a99d76c1a4..e530b87d26 100644 --- a/app/javascript/flavours/glitch/features/ui/components/compose_panel.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/compose_panel.jsx @@ -7,16 +7,13 @@ import { mountCompose, unmountCompose } from 'flavours/glitch/actions/compose'; import ServerBanner from 'flavours/glitch/components/server_banner'; import ComposeFormContainer from 'flavours/glitch/features/compose/containers/compose_form_container'; import SearchContainer from 'flavours/glitch/features/compose/containers/search_container'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import LinkFooter from './link_footer'; class ComposePanel extends PureComponent { - - static contextTypes = { - identity: PropTypes.object.isRequired, - }; - static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, }; @@ -31,7 +28,7 @@ class ComposePanel extends PureComponent { } render() { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; return (
@@ -55,4 +52,4 @@ class ComposePanel extends PureComponent { } -export default connect()(ComposePanel); +export default connect()(withIdentity(ComposePanel)); diff --git a/app/javascript/flavours/glitch/features/ui/components/header.jsx b/app/javascript/flavours/glitch/features/ui/components/header.jsx index 618a6b63d4..f102912faa 100644 --- a/app/javascript/flavours/glitch/features/ui/components/header.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/header.jsx @@ -14,6 +14,7 @@ import { Avatar } from 'flavours/glitch/components/avatar'; import { Icon } from 'flavours/glitch/components/icon'; import { WordmarkLogo, SymbolLogo } from 'flavours/glitch/components/logo'; import { Permalink } from 'flavours/glitch/components/permalink'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { registrationsOpen, me, sso_redirect } from 'flavours/glitch/initial_state'; const Account = connect(state => ({ @@ -42,12 +43,8 @@ const mapDispatchToProps = (dispatch) => ({ }); class Header extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, openClosedRegistrationsModal: PropTypes.func, location: PropTypes.object, signupUrl: PropTypes.string.isRequired, @@ -61,7 +58,7 @@ class Header extends PureComponent { } render () { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const { location, openClosedRegistrationsModal, signupUrl, intl } = this.props; let content; @@ -122,4 +119,4 @@ class Header extends PureComponent { } -export default injectIntl(withRouter(connect(mapStateToProps, mapDispatchToProps)(Header))); +export default injectIntl(withRouter(withIdentity(connect(mapStateToProps, mapDispatchToProps)(Header)))); diff --git a/app/javascript/flavours/glitch/features/ui/components/link_footer.jsx b/app/javascript/flavours/glitch/features/ui/components/link_footer.jsx index 6741552731..7c0ece465f 100644 --- a/app/javascript/flavours/glitch/features/ui/components/link_footer.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/link_footer.jsx @@ -8,6 +8,7 @@ import { Link } from 'react-router-dom'; import { connect } from 'react-redux'; import { openModal } from 'flavours/glitch/actions/modal'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { domain, version, source_url, statusPageUrl, profile_directory as profileDirectory } from 'flavours/glitch/initial_state'; import { PERMISSION_INVITE_USERS } from 'flavours/glitch/permissions'; import { logOut } from 'flavours/glitch/utils/log_out'; @@ -32,12 +33,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }); class LinkFooter extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, multiColumn: PropTypes.bool, onLogout: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, @@ -53,7 +50,7 @@ class LinkFooter extends PureComponent { }; render () { - const { signedIn, permissions } = this.context.identity; + const { signedIn, permissions } = this.props.identity; const { multiColumn } = this.props; const canInvite = signedIn && ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS); @@ -108,4 +105,4 @@ class LinkFooter extends PureComponent { } -export default injectIntl(connect(null, mapDispatchToProps)(LinkFooter)); +export default injectIntl(withIdentity(connect(null, mapDispatchToProps)(LinkFooter))); diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx index fa1df612fa..98d82342cf 100644 --- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx @@ -30,6 +30,7 @@ import StarIcon from '@/material-icons/400-24px/star.svg?react'; import { fetchFollowRequests } from 'flavours/glitch/actions/accounts'; import { IconWithBadge } from 'flavours/glitch/components/icon_with_badge'; import { NavigationPortal } from 'flavours/glitch/components/navigation_portal'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { timelinePreview, trendsEnabled } from 'flavours/glitch/initial_state'; import { transientSingleColumn } from 'flavours/glitch/is_mobile'; import { preferencesLink } from 'flavours/glitch/utils/backend_links'; @@ -98,12 +99,8 @@ const FollowRequestsLink = () => { }; class NavigationPanel extends Component { - - static contextTypes = { - identity: PropTypes.object.isRequired, - }; - static propTypes = { + identity: identityContextPropShape, intl: PropTypes.object.isRequired, onOpenSettings: PropTypes.func, }; @@ -114,7 +111,7 @@ class NavigationPanel extends Component { render () { const { intl, onOpenSettings } = this.props; - const { signedIn, disabledAccountId } = this.context.identity; + const { signedIn, disabledAccountId } = this.props.identity; let banner = undefined; @@ -188,4 +185,4 @@ class NavigationPanel extends Component { } -export default injectIntl(NavigationPanel); +export default injectIntl(withIdentity(NavigationPanel)); diff --git a/app/javascript/flavours/glitch/features/ui/index.jsx b/app/javascript/flavours/glitch/features/ui/index.jsx index c257b8cdf5..4a7b9ebfde 100644 --- a/app/javascript/flavours/glitch/features/ui/index.jsx +++ b/app/javascript/flavours/glitch/features/ui/index.jsx @@ -17,6 +17,7 @@ import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'flavour import { INTRODUCTION_VERSION } from 'flavours/glitch/actions/onboarding'; import { Permalink } from 'flavours/glitch/components/permalink'; import { PictureInPicture } from 'flavours/glitch/features/picture_in_picture'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { layoutFromWindow } from 'flavours/glitch/is_mobile'; import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; @@ -129,12 +130,8 @@ const keyMap = { }; class SwitchingColumnsArea extends PureComponent { - - static contextTypes = { - identity: PropTypes.object, - }; - static propTypes = { + identity: identityContextPropShape, children: PropTypes.node, location: PropTypes.object, singleColumn: PropTypes.bool, @@ -169,7 +166,7 @@ class SwitchingColumnsArea extends PureComponent { render () { const { children, singleColumn } = this.props; - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; const pathName = this.props.location.pathname; let redirect; @@ -262,12 +259,8 @@ class SwitchingColumnsArea extends PureComponent { } class UI extends PureComponent { - - static contextTypes = { - identity: PropTypes.object.isRequired, - }; - static propTypes = { + identity: identityContextPropShape, dispatch: PropTypes.func.isRequired, children: PropTypes.node, isWide: PropTypes.bool, @@ -323,7 +316,7 @@ class UI extends PureComponent { this.dragTargets.push(e.target); } - if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore && this.context.identity.signedIn) { + if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore && this.props.identity.signedIn) { this.setState({ draggingOver: true }); } }; @@ -351,7 +344,7 @@ class UI extends PureComponent { this.setState({ draggingOver: false }); this.dragTargets = []; - if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore && this.context.identity.signedIn) { + if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore && this.props.identity.signedIn) { this.props.dispatch(uploadCompose(e.dataTransfer.files)); } }; @@ -403,7 +396,7 @@ class UI extends PureComponent { }; componentDidMount () { - const { signedIn } = this.context.identity; + const { signedIn } = this.props.identity; window.addEventListener('beforeunload', this.handleBeforeUnload, false); window.addEventListener('resize', this.handleResize, { passive: true }); @@ -649,7 +642,7 @@ class UI extends PureComponent {
- + {children} @@ -665,4 +658,4 @@ class UI extends PureComponent { } -export default connect(mapStateToProps)(injectIntl(withRouter(UI))); +export default connect(mapStateToProps)(injectIntl(withRouter(withIdentity(UI)))); diff --git a/app/javascript/flavours/glitch/identity_context.tsx b/app/javascript/flavours/glitch/identity_context.tsx new file mode 100644 index 0000000000..28dcb1f14b --- /dev/null +++ b/app/javascript/flavours/glitch/identity_context.tsx @@ -0,0 +1,74 @@ +import PropTypes from 'prop-types'; +import { createContext, useContext } from 'react'; + +import hoistStatics from 'hoist-non-react-statics'; + +import type { InitialState } from 'flavours/glitch/initial_state'; + +export interface IdentityContextType { + signedIn: boolean; + accountId: string | undefined; + disabledAccountId: string | undefined; + accessToken: string | undefined; + permissions: number; +} + +export const identityContextPropShape = PropTypes.shape({ + signedIn: PropTypes.bool.isRequired, + accountId: PropTypes.string, + disabledAccountId: PropTypes.string, + accessToken: PropTypes.string, +}).isRequired; + +export const createIdentityContext = (state: InitialState) => ({ + signedIn: !!state.meta.me, + accountId: state.meta.me, + disabledAccountId: state.meta.disabled_account_id, + accessToken: state.meta.access_token, + permissions: state.role?.permissions ?? 0, +}); + +export const IdentityContext = createContext({ + signedIn: false, + permissions: 0, + accountId: undefined, + disabledAccountId: undefined, + accessToken: undefined, +}); + +export const useIdentity = () => useContext(IdentityContext); + +export interface IdentityProps { + ref?: unknown; + wrappedComponentRef?: unknown; +} + +/* Injects an `identity` props into the wrapped component to be able to use the new context in class components */ +export function withIdentity< + ComponentType extends React.ComponentType, +>(Component: ComponentType) { + const displayName = `withIdentity(${Component.displayName ?? Component.name})`; + const C = (props: React.ComponentProps) => { + const { wrappedComponentRef, ...remainingProps } = props; + + return ( + + {(context) => { + return ( + // @ts-expect-error - Dynamic covariant generic components are tough to type. + + ); + }} + + ); + }; + + C.displayName = displayName; + C.WrappedComponent = Component; + + return hoistStatics(C, Component); +} diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index 3e84966cb4..1a40810418 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -50,12 +50,22 @@ * @property {string} default_content_type */ +/** + * @typedef Role + * @property {string} id + * @property {string} name + * @property {string} permissions + * @property {string} color + * @property {boolean} highlighted + */ + /** * @typedef InitialState * @property {Record} accounts * @property {InitialStateLanguage[]} languages * @property {boolean=} critical_updates_pending * @property {InitialStateMeta} meta + * @property {Role?} role * @property {object} local_settings * @property {number} max_feed_hashtags * @property {number} poll_limits From 2bcbeed95143448625eccbbf3a3245a1eec26dce Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 20 May 2024 16:59:23 +0200 Subject: [PATCH 205/658] Add some error handling to OTP secret migration (#30344) --- ...80905_migrate_devise_two_factor_secrets.rb | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb b/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb index 360e4806da..6194cf9ee3 100644 --- a/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb +++ b/db/post_migrate/20240307180905_migrate_devise_two_factor_secrets.rb @@ -18,7 +18,13 @@ class MigrateDeviseTwoFactorSecrets < ActiveRecord::Migration[7.1] users_with_otp_enabled.find_each do |user| # Gets the new value on already-updated users # Falls back to legacy value on not-yet-migrated users - otp_secret = user.otp_secret + otp_secret = begin + user.otp_secret + rescue OpenSSL::OpenSSLError + next if ENV['MIGRATION_IGNORE_INVALID_OTP_SECRET'] == 'true' + + abort_with_decryption_error(user) + end Rails.logger.debug { "Processing #{user.email}" } @@ -36,4 +42,22 @@ class MigrateDeviseTwoFactorSecrets < ActiveRecord::Migration[7.1] def users_with_otp_enabled MigrationUser.where(otp_required_for_login: true, otp_secret: nil) end + + def abort_with_decryption_error(user) + abort <<~MESSAGE + + ERROR: Unable to decrypt OTP secret for user #{user.id}. + + This is most likely because you have changed the value of `OTP_SECRET` at some point in + time after the user configured 2FA. + + In this case, their OTP secret had already been lost with the change to `OTP_SECRET`, and + proceeding with this migration will not make the situation worse. + + Please double-check that you have not accidentally changed `OTP_SECRET` just for this + migration, and re-run the migration with `MIGRATION_IGNORE_INVALID_OTP_SECRET=true`. + + Migration aborted. + MESSAGE + end end From 00cf8d37480b053b179e1caa12c5e9fc04813a4b Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 20 May 2024 16:59:27 +0200 Subject: [PATCH 206/658] Change older Paperclip database migrations for consistency (#30204) --- .../20160227230233_add_attachment_avatar_to_accounts.rb | 6 +++++- .../20160312193225_add_attachment_header_to_accounts.rb | 6 +++++- db/migrate/20160905150353_create_media_attachments.rb | 8 +++++++- .../20170330164118_add_attachment_data_to_imports.rb | 6 +++++- db/migrate/20170901141119_truncate_preview_cards.rb | 8 +++++++- db/migrate/20170913000752_create_site_uploads.rb | 8 +++++++- db/migrate/20170917153509_create_custom_emojis.rb | 7 ++++++- ...27125810_add_thumbnail_columns_to_media_attachments.rb | 7 ++++++- 8 files changed, 48 insertions(+), 8 deletions(-) diff --git a/db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb b/db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb index 3666abf1cc..534df25eed 100644 --- a/db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb +++ b/db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb @@ -3,7 +3,11 @@ class AddAttachmentAvatarToAccounts < ActiveRecord::Migration[4.2] def self.up change_table :accounts do |t| - t.attachment :avatar + # The following corresponds to `t.attachment :avatar` in an older version of Paperclip + t.string :avatar_file_name + t.string :avatar_content_type + t.integer :avatar_file_size + t.datetime :avatar_updated_at end end diff --git a/db/migrate/20160312193225_add_attachment_header_to_accounts.rb b/db/migrate/20160312193225_add_attachment_header_to_accounts.rb index 37108fc189..b481fc5290 100644 --- a/db/migrate/20160312193225_add_attachment_header_to_accounts.rb +++ b/db/migrate/20160312193225_add_attachment_header_to_accounts.rb @@ -3,7 +3,11 @@ class AddAttachmentHeaderToAccounts < ActiveRecord::Migration[4.2] def self.up change_table :accounts do |t| - t.attachment :header + # The following corresponds to `t.attachment :header` in an older version of Paperclip + t.string :header_file_name + t.string :header_content_type + t.integer :header_file_size + t.datetime :header_updated_at end end diff --git a/db/migrate/20160905150353_create_media_attachments.rb b/db/migrate/20160905150353_create_media_attachments.rb index 3903a7b9a1..92680db9f3 100644 --- a/db/migrate/20160905150353_create_media_attachments.rb +++ b/db/migrate/20160905150353_create_media_attachments.rb @@ -4,7 +4,13 @@ class CreateMediaAttachments < ActiveRecord::Migration[5.0] def change create_table :media_attachments do |t| t.integer :status_id, null: true, default: nil - t.attachment :file + + # The following corresponds to `t.attachment :file` in an older version of Paperclip + t.string :file_file_name + t.string :file_content_type + t.integer :file_file_size + t.datetime :file_updated_at + t.string :remote_url, null: false, default: '' t.integer :account_id diff --git a/db/migrate/20170330164118_add_attachment_data_to_imports.rb b/db/migrate/20170330164118_add_attachment_data_to_imports.rb index 908d4da96a..0daaa9d02e 100644 --- a/db/migrate/20170330164118_add_attachment_data_to_imports.rb +++ b/db/migrate/20170330164118_add_attachment_data_to_imports.rb @@ -3,7 +3,11 @@ class AddAttachmentDataToImports < ActiveRecord::Migration[4.2] def self.up change_table :imports do |t| - t.attachment :data + # The following corresponds to `t.attachment :data` in an older version of Paperclip + t.string :data_file_name + t.string :data_content_type + t.integer :data_file_size + t.datetime :data_updated_at end end diff --git a/db/migrate/20170901141119_truncate_preview_cards.rb b/db/migrate/20170901141119_truncate_preview_cards.rb index b4ba8c45ea..f251841f2e 100644 --- a/db/migrate/20170901141119_truncate_preview_cards.rb +++ b/db/migrate/20170901141119_truncate_preview_cards.rb @@ -8,7 +8,13 @@ class TruncatePreviewCards < ActiveRecord::Migration[5.1] t.string :url, default: '', null: false, index: { unique: true } t.string :title, default: '', null: false t.string :description, default: '', null: false - t.attachment :image + + # The following corresponds to `t.attachment :image` in an older version of Paperclip + t.string :image_file_name + t.string :image_content_type + t.integer :image_file_size + t.datetime :image_updated_at + t.integer :type, default: 0, null: false t.text :html, default: '', null: false t.string :author_name, default: '', null: false diff --git a/db/migrate/20170913000752_create_site_uploads.rb b/db/migrate/20170913000752_create_site_uploads.rb index 43a793806f..16a95ea013 100644 --- a/db/migrate/20170913000752_create_site_uploads.rb +++ b/db/migrate/20170913000752_create_site_uploads.rb @@ -4,7 +4,13 @@ class CreateSiteUploads < ActiveRecord::Migration[5.1] def change create_table :site_uploads do |t| t.string :var, default: '', null: false, index: { unique: true } - t.attachment :file + + # The following corresponds to `t.attachment :file` in an older version of Paperclip + t.string :file_file_name + t.string :file_content_type + t.integer :file_file_size + t.datetime :file_updated_at + t.json :meta t.timestamps end diff --git a/db/migrate/20170917153509_create_custom_emojis.rb b/db/migrate/20170917153509_create_custom_emojis.rb index 984fcd2181..dedc8cde80 100644 --- a/db/migrate/20170917153509_create_custom_emojis.rb +++ b/db/migrate/20170917153509_create_custom_emojis.rb @@ -5,7 +5,12 @@ class CreateCustomEmojis < ActiveRecord::Migration[5.1] create_table :custom_emojis do |t| t.string :shortcode, null: false, default: '' t.string :domain - t.attachment :image + + # The following corresponds to `t.attachment :image` in an older version of Paperclip + t.string :image_file_name + t.string :image_content_type + t.integer :image_file_size + t.datetime :image_updated_at t.timestamps end diff --git a/db/migrate/20200627125810_add_thumbnail_columns_to_media_attachments.rb b/db/migrate/20200627125810_add_thumbnail_columns_to_media_attachments.rb index a3c6b55fd2..c11a24e8b5 100644 --- a/db/migrate/20200627125810_add_thumbnail_columns_to_media_attachments.rb +++ b/db/migrate/20200627125810_add_thumbnail_columns_to_media_attachments.rb @@ -2,7 +2,12 @@ class AddThumbnailColumnsToMediaAttachments < ActiveRecord::Migration[5.2] def up - add_attachment :media_attachments, :thumbnail + # The following corresponds to `add_attachment :media_attachments, :thumbnail` in an older version of Paperclip + add_column :media_attachments, :thumbnail_file_name, :string + add_column :media_attachments, :thumbnail_content_type, :string + add_column :media_attachments, :thumbnail_file_size, :integer + add_column :media_attachments, :thumbnail_updated_at, :datetime + add_column :media_attachments, :thumbnail_remote_url, :string end From 0a2110b9af52005798251dc9d245a66dd5dd20fa Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 20 May 2024 11:00:09 -0400 Subject: [PATCH 207/658] Add coverage for custom filters (#30347) --- spec/system/filters_spec.rb | 72 +++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 spec/system/filters_spec.rb diff --git a/spec/system/filters_spec.rb b/spec/system/filters_spec.rb new file mode 100644 index 0000000000..9d18e90460 --- /dev/null +++ b/spec/system/filters_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Filters' do + let(:user) { Fabricate(:user) } + let(:filter_title) { 'Filter of fun and games' } + + before { sign_in(user) } + + describe 'Creating a filter' do + it 'Populates a new filter from form' do + navigate_to_filters + + click_on I18n.t('filters.new.title') + fill_in_filter_form + expect(page).to have_content(filter_title) + end + end + + describe 'Editing an existing filter' do + let(:new_title) { 'Change title value' } + + before { Fabricate :custom_filter, account: user.account, title: filter_title } + + it 'Updates the saved filter' do + navigate_to_filters + + click_on filter_title + + fill_in filter_title_field, with: new_title + click_on I18n.t('generic.save_changes') + + expect(page).to have_content(new_title) + end + end + + describe 'Destroying an existing filter' do + before { Fabricate :custom_filter, account: user.account, title: filter_title } + + it 'Deletes the filter' do + navigate_to_filters + + expect(page).to have_content filter_title + expect do + click_on I18n.t('filters.index.delete') + end.to change(CustomFilter, :count).by(-1) + + expect(page).to_not have_content(filter_title) + end + end + + def navigate_to_filters + visit settings_path + + click_on I18n.t('filters.index.title') + expect(page).to have_content I18n.t('filters.index.title') + end + + def fill_in_filter_form + fill_in filter_title_field, with: filter_title + check I18n.t('filters.contexts.home') + within('.custom_filter_keywords_keyword') do + fill_in with: 'Keyword' + end + click_on I18n.t('filters.new.save') + end + + def filter_title_field + I18n.t('simple_form.labels.defaults.title') + end +end From 8c925dec793476b0f516aab901c7802d8e04f844 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 19:04:21 +0200 Subject: [PATCH 208/658] chore(deps): update dependency rubocop-rails to v2.25.0 (#30341) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index eade99acfd..f1a1d2a938 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -425,7 +425,7 @@ GEM mime-types-data (3.2024.0507) mini_mime (1.1.5) mini_portile2 (2.8.6) - minitest (5.22.3) + minitest (5.23.0) msgpack (1.7.2) multi_json (1.15.0) multipart-post (2.4.0) @@ -610,7 +610,7 @@ GEM pundit (2.3.2) activesupport (>= 3.0.0) raabro (1.4.0) - racc (1.7.3) + racc (1.8.0) rack (2.2.9) rack-attack (6.7.0) rack (>= 1.0, < 4) @@ -685,7 +685,7 @@ GEM redis (>= 4) redlock (1.3.2) redis (>= 3.0.0, < 6.0) - regexp_parser (2.9.0) + regexp_parser (2.9.2) reline (0.5.7) io-console (~> 0.5) request_store (1.6.0) @@ -746,7 +746,7 @@ GEM rubocop-performance (1.21.0) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rails (2.24.1) + rubocop-rails (2.25.0) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) From 0663c7d78d7de406ed199f61fd0cdb55b14b8f1f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 19:14:10 +0200 Subject: [PATCH 209/658] fix(deps): update formatjs monorepo (#30359) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 139 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 44 deletions(-) diff --git a/yarn.lock b/yarn.lock index 698824cab4..2d27d1302a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2259,6 +2259,16 @@ __metadata: languageName: node linkType: hard +"@formatjs/ecma402-abstract@npm:2.0.0": + version: 2.0.0 + resolution: "@formatjs/ecma402-abstract@npm:2.0.0" + dependencies: + "@formatjs/intl-localematcher": "npm:0.5.4" + tslib: "npm:^2.4.0" + checksum: 10c0/94cba291aeadffa3ca416087c2c2352c8a741bb4dcb7f47f15c247b1f043ffcef1af5b20a1b7578fbba9e704fc5f1c079923f3537a273d50162be62f8037625c + languageName: node + linkType: hard + "@formatjs/fast-memoize@npm:2.2.0": version: 2.2.0 resolution: "@formatjs/fast-memoize@npm:2.2.0" @@ -2279,6 +2289,17 @@ __metadata: languageName: node linkType: hard +"@formatjs/icu-messageformat-parser@npm:2.7.8": + version: 2.7.8 + resolution: "@formatjs/icu-messageformat-parser@npm:2.7.8" + dependencies: + "@formatjs/ecma402-abstract": "npm:2.0.0" + "@formatjs/icu-skeleton-parser": "npm:1.8.2" + tslib: "npm:^2.4.0" + checksum: 10c0/a3b759a825fb22ffd7b906f6a07b1a079bbc34f72c745de2c2514e439c4bb75bc1a9442eba1bac7ff3ea3010e12076374cd755ad12116b1d066cc90da5fbcbc9 + languageName: node + linkType: hard + "@formatjs/icu-skeleton-parser@npm:1.8.0": version: 1.8.0 resolution: "@formatjs/icu-skeleton-parser@npm:1.8.0" @@ -2289,25 +2310,35 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-displaynames@npm:6.6.6": - version: 6.6.6 - resolution: "@formatjs/intl-displaynames@npm:6.6.6" +"@formatjs/icu-skeleton-parser@npm:1.8.2": + version: 1.8.2 + resolution: "@formatjs/icu-skeleton-parser@npm:1.8.2" dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.2" - "@formatjs/intl-localematcher": "npm:0.5.4" + "@formatjs/ecma402-abstract": "npm:2.0.0" tslib: "npm:^2.4.0" - checksum: 10c0/4ba40057cfafaabf04485137bc96705d5ed7ac48f17ed7dfe8dbd7f71119667b6c0b7fa75469e32b70c9bada2c5d03af37a5261d655a37b81c63ba907edbb2e8 + checksum: 10c0/9b15013acc47b8d560b52942e3dab2abaaa9c5a4410bbd1d490a4b22bf5ca36fdd88b71f241d05479bddf856d0d1d57b7ecc9e79738497ac518616aa6d4d0015 languageName: node linkType: hard -"@formatjs/intl-listformat@npm:7.5.5": - version: 7.5.5 - resolution: "@formatjs/intl-listformat@npm:7.5.5" +"@formatjs/intl-displaynames@npm:6.6.8": + version: 6.6.8 + resolution: "@formatjs/intl-displaynames@npm:6.6.8" dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.2" + "@formatjs/ecma402-abstract": "npm:2.0.0" "@formatjs/intl-localematcher": "npm:0.5.4" tslib: "npm:^2.4.0" - checksum: 10c0/bc9d8cbe42bd9513db0b2b221c0b1a752892005a90fa629b4cf7df1cbd3b96997cddbf420e562ebdfdc691a28d9b759ccae9633d5987aa0bceed5aef77a07ca4 + checksum: 10c0/1a03e7644022741c1bcf10fcd07da88c434416a13603ace693a038114010463307b4130d3a3f53ad5665bd27fca9a6b19ac8e5bf58e17598b1ea84db173fdfbb + languageName: node + linkType: hard + +"@formatjs/intl-listformat@npm:7.5.7": + version: 7.5.7 + resolution: "@formatjs/intl-listformat@npm:7.5.7" + dependencies: + "@formatjs/ecma402-abstract": "npm:2.0.0" + "@formatjs/intl-localematcher": "npm:0.5.4" + tslib: "npm:^2.4.0" + checksum: 10c0/5d0478752d669d87c82aa80880df464d64a1c8974fcb6136bc854567f570a1696e5468005ffa266cfcb623adb7c7299b839c06ea33897f55d35dab6a7575cc84 languageName: node linkType: hard @@ -2321,33 +2352,33 @@ __metadata: linkType: hard "@formatjs/intl-pluralrules@npm:^5.2.2": - version: 5.2.12 - resolution: "@formatjs/intl-pluralrules@npm:5.2.12" + version: 5.2.14 + resolution: "@formatjs/intl-pluralrules@npm:5.2.14" dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.2" + "@formatjs/ecma402-abstract": "npm:2.0.0" "@formatjs/intl-localematcher": "npm:0.5.4" tslib: "npm:^2.4.0" - checksum: 10c0/0f4d9f4f272dd962b2f742519045ad43a1b6358755787d3394efcc5884b02184cc8d76fb13d98b1f30c41a813b81f82dd2342e1fb0fbd7b7efa69f5d0d59c4d0 + checksum: 10c0/3c00109c8d4c8b221c2b9af38a38d31cd6293a0a412a1f2cdae2b8ef81bd71626c9ff4a647389682cb27ae5c223bd6f64ef54d03e3f6f19c372e0c6194b76b38 languageName: node linkType: hard -"@formatjs/intl@npm:2.10.2": - version: 2.10.2 - resolution: "@formatjs/intl@npm:2.10.2" +"@formatjs/intl@npm:2.10.4": + version: 2.10.4 + resolution: "@formatjs/intl@npm:2.10.4" dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.2" + "@formatjs/ecma402-abstract": "npm:2.0.0" "@formatjs/fast-memoize": "npm:2.2.0" - "@formatjs/icu-messageformat-parser": "npm:2.7.6" - "@formatjs/intl-displaynames": "npm:6.6.6" - "@formatjs/intl-listformat": "npm:7.5.5" - intl-messageformat: "npm:10.5.12" + "@formatjs/icu-messageformat-parser": "npm:2.7.8" + "@formatjs/intl-displaynames": "npm:6.6.8" + "@formatjs/intl-listformat": "npm:7.5.7" + intl-messageformat: "npm:10.5.14" tslib: "npm:^2.4.0" peerDependencies: typescript: ^4.7 || 5 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/20df407e141055e8c7b2605c06e952b643be7ea01d992862e13fc623ca2db034069744eae2be16655bf7888b3add1bfc2653fd0a08bcfdb67fb9b72a306f7718 + checksum: 10c0/ca7877e962f73f1fe0e358f12d73bdc3ec4006c14ee801e06d9f7aef06bcdcc12355a8f53f32b0e890f829949ded35e825c914ca5f4709eb1e08c2a18c1368c2 languageName: node linkType: hard @@ -2371,6 +2402,26 @@ __metadata: languageName: node linkType: hard +"@formatjs/ts-transformer@npm:3.13.14": + version: 3.13.14 + resolution: "@formatjs/ts-transformer@npm:3.13.14" + dependencies: + "@formatjs/icu-messageformat-parser": "npm:2.7.8" + "@types/json-stable-stringify": "npm:^1.0.32" + "@types/node": "npm:14 || 16 || 17" + chalk: "npm:^4.0.0" + json-stable-stringify: "npm:^1.0.1" + tslib: "npm:^2.4.0" + typescript: "npm:5" + peerDependencies: + ts-jest: ">=27" + peerDependenciesMeta: + ts-jest: + optional: true + checksum: 10c0/38450cfce3ec5132f3548c1e9ab098909ca8d2db2b8b6b4b5bb87aa59a4ca1a19bbf6d339ace39bcc931fa80d9946b4c7cf039c9574069b317ae015cd6963bd3 + languageName: node + linkType: hard + "@gamestdio/websocket@npm:^0.3.2": version: 0.3.2 resolution: "@gamestdio/websocket@npm:0.3.2" @@ -5197,21 +5248,21 @@ __metadata: linkType: hard "babel-plugin-formatjs@npm:^10.5.1": - version: 10.5.14 - resolution: "babel-plugin-formatjs@npm:10.5.14" + version: 10.5.16 + resolution: "babel-plugin-formatjs@npm:10.5.16" dependencies: "@babel/core": "npm:^7.10.4" "@babel/helper-plugin-utils": "npm:^7.10.4" "@babel/plugin-syntax-jsx": "npm:7" "@babel/traverse": "npm:7" "@babel/types": "npm:^7.12.11" - "@formatjs/icu-messageformat-parser": "npm:2.7.6" - "@formatjs/ts-transformer": "npm:3.13.12" + "@formatjs/icu-messageformat-parser": "npm:2.7.8" + "@formatjs/ts-transformer": "npm:3.13.14" "@types/babel__core": "npm:^7.1.7" "@types/babel__helper-plugin-utils": "npm:^7.10.0" "@types/babel__traverse": "npm:^7.1.7" tslib: "npm:^2.4.0" - checksum: 10c0/78d33f0304c7b6e36334b2f32bacd144cbbe08cb22318ff994e7adc7705b7f8208354c9af9f87b4390d11aee1ea81cfee9f224a57fe5265173b92ee7de921359 + checksum: 10c0/03d9d2b0b9cdc05c011bfb417a43e5c0f557868ed84d83acbc3cb9072b7fa98f5219473d0bd61f02741c151d6f2162da363bd337522c80af14721ae37f6da86b languageName: node linkType: hard @@ -9643,15 +9694,15 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.5.12, intl-messageformat@npm:^10.3.5": - version: 10.5.12 - resolution: "intl-messageformat@npm:10.5.12" +"intl-messageformat@npm:10.5.14, intl-messageformat@npm:^10.3.5": + version: 10.5.14 + resolution: "intl-messageformat@npm:10.5.14" dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.2" + "@formatjs/ecma402-abstract": "npm:2.0.0" "@formatjs/fast-memoize": "npm:2.2.0" - "@formatjs/icu-messageformat-parser": "npm:2.7.6" + "@formatjs/icu-messageformat-parser": "npm:2.7.8" tslib: "npm:^2.4.0" - checksum: 10c0/f95734e98a05ef7f51de0c27904d3a994528e3a174963bd1b3a6db9416b5fd84bbd8f7d26d84fc547d51af69ccf46dd3f73a3f4f20a2ccef5c9cd90e946ad82c + checksum: 10c0/8ec0a60539f67039356e211bcc8d81cf1bd9d62190a72ab0e94504da92f0242fe2f94ffb512b97cc6f63782b7891874d4038536ce04631e59d762c3441c60b4b languageName: node linkType: hard @@ -14353,18 +14404,18 @@ __metadata: linkType: hard "react-intl@npm:^6.4.2": - version: 6.6.6 - resolution: "react-intl@npm:6.6.6" + version: 6.6.8 + resolution: "react-intl@npm:6.6.8" dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.2" - "@formatjs/icu-messageformat-parser": "npm:2.7.6" - "@formatjs/intl": "npm:2.10.2" - "@formatjs/intl-displaynames": "npm:6.6.6" - "@formatjs/intl-listformat": "npm:7.5.5" + "@formatjs/ecma402-abstract": "npm:2.0.0" + "@formatjs/icu-messageformat-parser": "npm:2.7.8" + "@formatjs/intl": "npm:2.10.4" + "@formatjs/intl-displaynames": "npm:6.6.8" + "@formatjs/intl-listformat": "npm:7.5.7" "@types/hoist-non-react-statics": "npm:^3.3.1" "@types/react": "npm:16 || 17 || 18" hoist-non-react-statics: "npm:^3.3.2" - intl-messageformat: "npm:10.5.12" + intl-messageformat: "npm:10.5.14" tslib: "npm:^2.4.0" peerDependencies: react: ^16.6.0 || 17 || 18 @@ -14372,7 +14423,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/04c1d1ca783f2a5e605544290c93e57629500be6811d7c2c3342903bf9f9a720d2e4c9cf3924133bf84e510ee879bf3d870a3ff269f5b197f894a49047bd089d + checksum: 10c0/7673507eb73ad4edd1593da7173cec68f316cf77037e0959900babd32d5984a39ba7fa10aaa0a23bcddb7b98daf7dd007cb73ddfc39127ede87c18ec780a519c languageName: node linkType: hard From 48b9837ad8fd2aad64896adaa2279528f0bf1d30 Mon Sep 17 00:00:00 2001 From: Essem Date: Mon, 20 May 2024 21:36:49 -0500 Subject: [PATCH 210/658] Fix building on systems with ICU 75 See brianmario/charlock_holmes#172 --- Gemfile | 2 +- Gemfile.lock | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 240dcce95a..f9aec7e70b 100644 --- a/Gemfile +++ b/Gemfile @@ -28,7 +28,7 @@ gem 'active_model_serializers', '~> 0.10' gem 'addressable', '~> 2.8' gem 'bootsnap', '~> 1.18.0', require: false gem 'browser' -gem 'charlock_holmes', '~> 0.7.7' +gem 'charlock_holmes', github: 'TheEssem/charlock_holmes', ref: '226932af4b03eb60d2e31d58b6c3efd72a3ace68' gem 'chewy', '~> 7.3' gem 'devise', '~> 4.9' gem 'devise-two-factor' diff --git a/Gemfile.lock b/Gemfile.lock index eade99acfd..f5d6580a80 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,6 +7,13 @@ GIT hkdf (~> 0.2) jwt (~> 2.0) +GIT + remote: https://github.com/TheEssem/charlock_holmes.git + revision: 226932af4b03eb60d2e31d58b6c3efd72a3ace68 + ref: 226932af4b03eb60d2e31d58b6c3efd72a3ace68 + specs: + charlock_holmes (0.7.7) + GEM remote: https://rubygems.org/ specs: @@ -159,7 +166,6 @@ GEM case_transform (0.2) activesupport cbor (0.5.9.8) - charlock_holmes (0.7.7) chewy (7.6.0) activesupport (>= 5.2) elasticsearch (>= 7.14.0, < 8) @@ -913,7 +919,7 @@ DEPENDENCIES browser bundler-audit (~> 0.9) capybara (~> 3.39) - charlock_holmes (~> 0.7.7) + charlock_holmes! chewy (~> 7.3) climate_control cocoon (~> 1.2) From 6c28810b39ec55083db9f8f98d8a9c317380acbf Mon Sep 17 00:00:00 2001 From: Jeremy Kescher Date: Tue, 21 May 2024 00:46:17 +0200 Subject: [PATCH 211/658] [Glitch+Emoji reactions] Use modern React context for for identity for emoji reaction code --- .../flavours/glitch/components/status.jsx | 26 +++++++++---------- .../status/components/detailed_status.jsx | 11 +++----- .../flavours/glitch/features/status/index.jsx | 4 +-- .../features/ui/util/identity_consumer.jsx | 16 ------------ 4 files changed, 18 insertions(+), 39 deletions(-) delete mode 100644 app/javascript/flavours/glitch/features/ui/util/identity_consumer.jsx diff --git a/app/javascript/flavours/glitch/components/status.jsx b/app/javascript/flavours/glitch/components/status.jsx index 0faa6d1dbd..d6205b1fcd 100644 --- a/app/javascript/flavours/glitch/components/status.jsx +++ b/app/javascript/flavours/glitch/components/status.jsx @@ -12,6 +12,7 @@ import { HotKeys } from 'react-hotkeys'; import PictureInPicturePlaceholder from 'flavours/glitch/components/picture_in_picture_placeholder'; import PollContainer from 'flavours/glitch/containers/poll_container'; import NotificationOverlayContainer from 'flavours/glitch/features/notifications/containers/overlay_container'; +import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning'; import { withOptionalRouter, WithOptionalRouterPropTypes } from 'flavours/glitch/utils/react_router'; @@ -20,7 +21,6 @@ import Card from '../features/status/components/card'; // to use the progress bar to show download progress import Bundle from '../features/ui/components/bundle'; import { MediaGallery, Video, Audio } from '../features/ui/util/async-components'; -import { IdentityConsumer } from '../features/ui/util/identity_consumer'; import { SensitiveMediaContext } from '../features/ui/util/sensitive_media_context'; import { displayMedia, visibleReactions } from '../initial_state'; @@ -78,6 +78,7 @@ class Status extends ImmutablePureComponent { static contextType = SensitiveMediaContext; static propTypes = { + identity: identityContextPropShape, containerId: PropTypes.string, id: PropTypes.string, status: ImmutablePropTypes.map, @@ -545,6 +546,7 @@ class Status extends ImmutablePureComponent { nextInReplyToId, rootId, history, + identity, ...other } = this.props; const { isCollapsed } = this.state; @@ -846,18 +848,14 @@ class Status extends ImmutablePureComponent { {...statusContentProps} /> - - {identity => ( - - )} - + {(!isCollapsed || !(muted || !settings.getIn(['collapsed', 'show_action_bar']))) && (
@@ -348,4 +345,4 @@ class DetailedStatus extends ImmutablePureComponent { } -export default withRouter(DetailedStatus); +export default withRouter(withIdentity(DetailedStatus)); diff --git a/app/javascript/flavours/glitch/features/status/index.jsx b/app/javascript/flavours/glitch/features/status/index.jsx index 95d33f2afb..4719689a8b 100644 --- a/app/javascript/flavours/glitch/features/status/index.jsx +++ b/app/javascript/flavours/glitch/features/status/index.jsx @@ -307,8 +307,8 @@ class Status extends ImmutablePureComponent { }; handleReactionAdd = (statusId, name, url) => { - const { dispatch } = this.props; - const { signedIn } = this.context.identity; + const { dispatch, identity } = this.props; + const { signedIn } = identity; if (signedIn) { dispatch(addReaction(statusId, name, url)); diff --git a/app/javascript/flavours/glitch/features/ui/util/identity_consumer.jsx b/app/javascript/flavours/glitch/features/ui/util/identity_consumer.jsx deleted file mode 100644 index bf7c7e70f9..0000000000 --- a/app/javascript/flavours/glitch/features/ui/util/identity_consumer.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; - -export class IdentityConsumer extends PureComponent { - static contextTypes = { - identity: PropTypes.object - }; - - static propTypes = { - children: PropTypes.func.isRequired - }; - - render() { - return this.props.children(this.context.identity); - } -} From eda2bdfc7abeb3f67d982ac009856489089ed7d7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 10:48:36 +0200 Subject: [PATCH 212/658] New Crowdin Translations (automated) (#30383) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/fil.json | 14 ++++++++++++++ config/locales/is.yml | 1 + config/locales/lt.yml | 6 +++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/fil.json b/app/javascript/mastodon/locales/fil.json index 894d73c8cc..3877276049 100644 --- a/app/javascript/mastodon/locales/fil.json +++ b/app/javascript/mastodon/locales/fil.json @@ -50,6 +50,8 @@ "admin.dashboard.retention.cohort_size": "Mga bagong tagagamit", "alert.rate_limited.message": "Mangyaring subukan muli pagkatapos ng {retry_time, time, medium}.", "audio.hide": "Itago ang tunog", + "block_modal.show_less": "Magpakita ng mas kaunti", + "block_modal.show_more": "Magpakita ng higit pa", "block_modal.title": "Harangan ang tagagamit?", "bundle_column_error.error.title": "Naku!", "bundle_column_error.network.body": "Nagkaroon ng kamalian habang sinusubukang i-karga ang pahinang ito. Maaaring dahil ito sa pansamantalang problema ng iyong koneksyon sa internet o ang server na ito.", @@ -102,6 +104,7 @@ "compose_form.encryption_warning": "Ang mga post sa Mastodon ay hindi naka-encrypt nang dulo-dulo. Huwag magbahagi ng anumang sensitibong impormasyon sa Mastodon.", "compose_form.hashtag_warning": "Hindi maililista ang post na ito sa anumang hashtag dahil hindi ito nakapubliko. Mga nakapublikong post lamang ang mahahanap ayon sa hashtag.", "compose_form.placeholder": "Anong nangyari?", + "compose_form.poll.duration": "Tagal ng botohan", "compose_form.poll.multiple": "Maraming pagpipilian", "compose_form.poll.single": "Piliin ang isa", "compose_form.reply": "Tumugon", @@ -173,6 +176,7 @@ "empty_column.list": "Wala pang laman ang listahang ito. Kapag naglathala ng mga bagong post ang mga miyembro ng listahang ito, makikita iyon dito.", "empty_column.lists": "Wala ka pang mga listahan. Kapag gumawa ka ng isa, makikita yun dito.", "explore.search_results": "Mga resulta ng paghahanap", + "explore.suggested_follows": "Mga tao", "explore.title": "Tuklasin", "explore.trending_links": "Mga balita", "filter_modal.select_filter.search": "Hanapin o gumawa", @@ -186,9 +190,13 @@ "follow_suggestions.who_to_follow": "Sinong maaaring sundan", "footer.about": "Tungkol dito", "footer.get_app": "Kunin ang app", + "footer.status": "Katayuan", "generic.saved": "Nakaimbak", "hashtag.column_header.tag_mode.all": "at {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", + "hashtag.column_settings.tag_mode.all": "Lahat ng nandito", + "hashtag.column_settings.tag_mode.any": "Ilan sa nandito", + "hashtag.column_settings.tag_mode.none": "Wala dito", "home.column_settings.show_replies": "Ipakita ang mga tugon", "home.pending_critical_update.body": "Mangyaring i-update ang iyong serbiro ng Mastodon sa lalong madaling panahon!", "interaction_modal.login.action": "Iuwi mo ako", @@ -199,6 +207,7 @@ "intervals.full.days": "{number, plural, one {# araw} other {# na araw}}", "intervals.full.hours": "{number, plural, one {# oras} other {# na oras}}", "intervals.full.minutes": "{number, plural, one {# minuto} other {# na minuto}}", + "keyboard_shortcuts.blocked": "Buksan ang talaan ng mga nakaharang na mga tagagamit", "keyboard_shortcuts.description": "Paglalarawan", "keyboard_shortcuts.down": "Ilipat pababa sa talaan", "keyboard_shortcuts.mention": "Banggitin ang may-akda", @@ -218,7 +227,10 @@ "navigation_bar.about": "Tungkol dito", "navigation_bar.blocks": "Nakaharang na mga tagagamit", "navigation_bar.direct": "Mga palihim na banggit", + "navigation_bar.discover": "Tuklasin", + "navigation_bar.explore": "Tuklasin", "navigation_bar.favourites": "Mga paborito", + "navigation_bar.follow_requests": "Mga hiling sa pagsunod", "navigation_bar.follows_and_followers": "Mga sinusundan at tagasunod", "navigation_bar.lists": "Mga listahan", "navigation_bar.search": "Maghanap", @@ -226,6 +238,7 @@ "notification.follow": "Sinundan ka ni {name}", "notification.follow_request": "Hinihiling ni {name} na sundan ka", "notification.mention": "Binanggit ka ni {name}", + "notification.moderation_warning": "Mayroong kang natanggap na babala sa pagtitimpi", "notification.relationships_severance_event.learn_more": "Matuto nang higit pa", "notification_requests.accept": "Tanggapin", "notification_requests.notifications_from": "Mga abiso mula kay/sa {name}", @@ -246,6 +259,7 @@ "onboarding.profile.note_hint": "Maaari mong @bangitin ang ibang mga tao o mga #hashtag…", "onboarding.profile.save_and_continue": "Iimbak at magpatuloy", "onboarding.share.next_steps": "Mga posibleng susunod na hakbang:", + "picture_in_picture.restore": "Ilagay ito pabalik", "poll.closed": "Sarado", "poll.reveal": "Ipakita ang mga resulta", "poll.voted": "Binoto mo para sa sagot na ito", diff --git a/config/locales/is.yml b/config/locales/is.yml index 2eeba976bc..9977752969 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -285,6 +285,7 @@ is: update_custom_emoji_html: "%{name} uppfærði tjáningartáknið %{target}" update_domain_block_html: "%{name} uppfærði útilokun lénsins %{target}" update_ip_block_html: "%{name} breytti reglu fyrir IP-vistfangið %{target}" + update_report_html: "%{name} uppfærði kæru %{target}" update_status_html: "%{name} uppfærði færslu frá %{target}" update_user_role_html: "%{name} breytti hlutverki %{target}" deleted_account: eyddur notandaaðgangur diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 552afa8301..3e514a547b 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -618,7 +618,7 @@ lt: settings: 'Keisti el. pašto nuostatas: %{link}' view: 'Peržiūra:' view_profile: Peržiurėti profilį - view_status: Peržiūrėti statusą + view_status: Peržiūrėti įrašą applications: created: Aplikacija sėkmingai sukurta destroyed: Aplikacija sėkmingai ištrinta @@ -777,8 +777,8 @@ lt: title: Moderacija notification_mailer: favourite: - body: 'Jūsų statusą pamėgo %{name}:' - subject: "%{name} pamėgo Jūsų statusą" + body: 'Tavo įrašą pamėgo %{name}:' + subject: "%{name} pamėgo tavo įrašą" title: Naujas mėgstamas follow: body: "%{name} pradėjo jus sekti!" From 89f89d738f5840c80ff938f8bf6734cdafe0fa83 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 21 May 2024 10:56:08 +0200 Subject: [PATCH 213/658] Revert "Allow unblocking email addresses from any matching account (#29305)" (#30385) --- app/controllers/admin/accounts_controller.rb | 2 +- app/models/canonical_email_block.rb | 1 - app/views/admin/accounts/show.html.haml | 2 +- spec/fabricators/canonical_email_block_fabricator.rb | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index d3be7817ff..9beb8fde6b 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -128,7 +128,7 @@ module Admin def unblock_email authorize @account, :unblock_email? - CanonicalEmailBlock.matching_account(@account).delete_all + CanonicalEmailBlock.where(reference_account: @account).delete_all log_action :unblock_email, @account diff --git a/app/models/canonical_email_block.rb b/app/models/canonical_email_block.rb index c05eb9801d..d09df6f5e2 100644 --- a/app/models/canonical_email_block.rb +++ b/app/models/canonical_email_block.rb @@ -20,7 +20,6 @@ class CanonicalEmailBlock < ApplicationRecord validates :canonical_email_hash, presence: true, uniqueness: true scope :matching_email, ->(email) { where(canonical_email_hash: email_to_canonical_email_hash(email)) } - scope :matching_account, ->(account) { matching_email(account&.user_email).or(where(reference_account: account)) } def to_log_human_identifier canonical_email_hash diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index bcf7c07314..f148b9a082 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -30,7 +30,7 @@ = render 'admin/accounts/counters', account: @account - if @account.local? && @account.user.nil? - = link_to t('admin.accounts.unblock_email'), unblock_email_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unblock_email, @account) && CanonicalEmailBlock.matching_account(@account).exists? + = link_to t('admin.accounts.unblock_email'), unblock_email_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unblock_email, @account) && CanonicalEmailBlock.exists?(reference_account_id: @account.id) - else .table-wrapper %table.table.inline-table diff --git a/spec/fabricators/canonical_email_block_fabricator.rb b/spec/fabricators/canonical_email_block_fabricator.rb index 2f979df794..1ef53ff4a4 100644 --- a/spec/fabricators/canonical_email_block_fabricator.rb +++ b/spec/fabricators/canonical_email_block_fabricator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true Fabricator(:canonical_email_block) do - email { |attrs| attrs[:reference_account] ? attrs[:reference_account].user_email : sequence(:email) { |i| "#{i}#{Faker::Internet.email}" } } + email { sequence(:email) { |i| "#{i}#{Faker::Internet.email}" } } reference_account { Fabricate.build(:account) } end From edf6ca56e369ebc7997f4f67a411afacf5e33911 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 21 May 2024 13:00:07 +0200 Subject: [PATCH 214/658] Fix rubocop error and cleanup `Status.as_direct_timeline` a little --- app/models/status.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/models/status.rb b/app/models/status.rb index ac90b2d03b..585a9fcb23 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -344,23 +344,23 @@ class Status < ApplicationRecord # _from_me part does not require any timeline filters query_from_me = where(account_id: account.id) - .where(Status.arel_table[:visibility].eq(3)) + .direct_visibility .limit(limit) - .order('statuses.id DESC') + .order(id: :desc) # _to_me part requires mute and block filter. # FIXME: may we check mutes.hide_notifications? query_to_me = Status + .direct_visibility .joins(:mentions) - .merge(Mention.where(account_id: account.id)) - .where(Status.arel_table[:visibility].eq(3)) + .where(mentions: { account_id: account.id }) .limit(limit) .order('mentions.status_id DESC') .not_excluded_by_account(account) if max_id.present? - query_from_me = query_from_me.where('statuses.id < ?', max_id) - query_to_me = query_to_me.where('mentions.status_id < ?', max_id) + query_from_me = query_from_me.where(id: ...max_id) + query_to_me = query_to_me.where(mentions: { status_id: ...max_id }) end if since_id.present? @@ -368,9 +368,9 @@ class Status < ApplicationRecord query_to_me = query_to_me.where('mentions.status_id > ?', since_id) end - # returns ActiveRecord.Relation - items = (query_from_me.select(:id).to_a + query_to_me.select(:id).to_a).uniq(&:id).sort_by(&:id).reverse.take(limit) - Status.where(id: items.map(&:id)) + # TODO: use a single query? + ids = (query_from_me.pluck(:id) + query_to_me.pluck(:id)).sort.uniq.reverse.take(limit) + Status.where(id: ids) end def favourites_map(status_ids, account_id) From 32223863a51472d929c57d22dbffc5d9c9fafa79 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 21 May 2024 15:17:34 +0200 Subject: [PATCH 215/658] Add coverage to `/admin/accounts/:id` (#30386) --- .../admin/accounts_controller_spec.rb | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb index b90bb414b0..f241d261b1 100644 --- a/spec/controllers/admin/accounts_controller_spec.rb +++ b/spec/controllers/admin/accounts_controller_spec.rb @@ -53,11 +53,32 @@ RSpec.describe Admin::AccountsController do describe 'GET #show' do let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - let(:account) { Fabricate(:account) } - it 'returns http success' do - get :show, params: { id: account.id } - expect(response).to have_http_status(200) + context 'with a remote account' do + let(:account) { Fabricate(:account, domain: 'example.com') } + + it 'returns http success' do + get :show, params: { id: account.id } + expect(response).to have_http_status(200) + end + end + + context 'with a local account' do + let(:account) { Fabricate(:account, domain: nil) } + + it 'returns http success' do + get :show, params: { id: account.id } + expect(response).to have_http_status(200) + end + end + + context 'with a local deleted account' do + let(:account) { Fabricate(:account, domain: nil, user: nil) } + + it 'returns http success' do + get :show, params: { id: account.id } + expect(response).to have_http_status(200) + end end end From cd0c5479362260082dbe1cbc42e364017853bbfc Mon Sep 17 00:00:00 2001 From: David Lapshin Date: Tue, 21 May 2024 18:24:51 +0300 Subject: [PATCH 216/658] Fix announcements icon rotating like settings one (#30388) --- app/javascript/styles/mastodon/components.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index f377eed95c..859c6e3267 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -4372,7 +4372,7 @@ a.status-card { color: $primary-text-color; } - .icon { + .icon-sliders { transform: rotate(60deg); } } @@ -4383,7 +4383,7 @@ a.status-card { } } -.no-reduce-motion .column-header__button .icon { +.no-reduce-motion .column-header__button .icon-sliders { transition: transform 150ms ease-in-out; } From dc35563f65e3c843b847c6d58797937200e27233 Mon Sep 17 00:00:00 2001 From: David Lapshin Date: Tue, 21 May 2024 18:24:51 +0300 Subject: [PATCH 217/658] [Glitch] Fix announcements icon rotating like settings one Port cd0c5479362260082dbe1cbc42e364017853bbfc to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/styles/components.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 9f102b847e..07b18b2936 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -4609,7 +4609,7 @@ a.status-card { color: $primary-text-color; } - .icon { + .icon-sliders { transform: rotate(60deg); } } @@ -4659,7 +4659,7 @@ a.status-card { padding: 0; } -.no-reduce-motion .column-header__button .icon { +.no-reduce-motion .column-header__button .icon-sliders { transition: transform 150ms ease-in-out; } From 6e67ca73f3b32bbac226b77f78acce52c525307b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 May 2024 09:35:27 +0200 Subject: [PATCH 218/658] fix(deps): update dependency axios to v1.7.2 (#30372) 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 2d27d1302a..9d97b2f157 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5196,13 +5196,13 @@ __metadata: linkType: hard "axios@npm:^1.4.0": - version: 1.6.8 - resolution: "axios@npm:1.6.8" + version: 1.7.2 + resolution: "axios@npm:1.7.2" dependencies: follow-redirects: "npm:^1.15.6" form-data: "npm:^4.0.0" proxy-from-env: "npm:^1.1.0" - checksum: 10c0/0f22da6f490335479a89878bc7d5a1419484fbb437b564a80c34888fc36759ae4f56ea28d55a191695e5ed327f0bad56e7ff60fb6770c14d1be6501505d47ab9 + checksum: 10c0/cbd47ce380fe045313364e740bb03b936420b8b5558c7ea36a4563db1258c658f05e40feb5ddd41f6633fdd96d37ac2a76f884dad599c5b0224b4c451b3fa7ae languageName: node linkType: hard From d9d4ba1b6f2756e819344b384d731c7722a931b5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 May 2024 09:47:49 +0200 Subject: [PATCH 219/658] fix(deps): update dependency glob to v10.3.16 (#30392) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9d97b2f157..9f953bb781 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8936,17 +8936,17 @@ __metadata: linkType: hard "glob@npm:^10.2.2, glob@npm:^10.2.6, glob@npm:^10.3.10, glob@npm:^10.3.7": - version: 10.3.15 - resolution: "glob@npm:10.3.15" + version: 10.3.16 + resolution: "glob@npm:10.3.16" dependencies: foreground-child: "npm:^3.1.0" - jackspeak: "npm:^2.3.6" + jackspeak: "npm:^3.1.2" minimatch: "npm:^9.0.1" minipass: "npm:^7.0.4" path-scurry: "npm:^1.11.0" bin: glob: dist/esm/bin.mjs - checksum: 10c0/cda748ddc181b31b3df9548c0991800406d5cc3b3f8110e37a8751ec1e39f37cdae7d7782d5422d7df92775121cdf00599992dff22f7ff1260344843af227c2b + checksum: 10c0/f7eb4c3e66f221f0be3967c02527047167967549bdf8ed1bd5f6277d43a35191af4e2bb8c89f07a79664958bae088fd06659e69a0f1de462972f1eab52a715e8 languageName: node linkType: hard @@ -10407,16 +10407,16 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^2.3.6": - version: 2.3.6 - resolution: "jackspeak@npm:2.3.6" +"jackspeak@npm:^3.1.2": + version: 3.1.2 + resolution: "jackspeak@npm:3.1.2" dependencies: "@isaacs/cliui": "npm:^8.0.2" "@pkgjs/parseargs": "npm:^0.11.0" dependenciesMeta: "@pkgjs/parseargs": optional: true - checksum: 10c0/f01d8f972d894cd7638bc338e9ef5ddb86f7b208ce177a36d718eac96ec86638a6efa17d0221b10073e64b45edc2ce15340db9380b1f5d5c5d000cbc517dc111 + checksum: 10c0/5f1922a1ca0f19869e23f0dc4374c60d36e922f7926c76fecf8080cc6f7f798d6a9caac1b9428327d14c67731fd551bb3454cb270a5e13a0718f3b3660ec3d5d languageName: node linkType: hard From a2b4c29c8fc8b7db163afffe1987fc4a41b574cb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 May 2024 09:57:51 +0200 Subject: [PATCH 220/658] New Crowdin Translations (automated) (#30394) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/fil.json | 10 +++++++++- app/javascript/mastodon/locales/lv.json | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/fil.json b/app/javascript/mastodon/locales/fil.json index 3877276049..1f9b0496b9 100644 --- a/app/javascript/mastodon/locales/fil.json +++ b/app/javascript/mastodon/locales/fil.json @@ -195,8 +195,9 @@ "hashtag.column_header.tag_mode.all": "at {additional}", "hashtag.column_header.tag_mode.any": "o {additional}", "hashtag.column_settings.tag_mode.all": "Lahat ng nandito", - "hashtag.column_settings.tag_mode.any": "Ilan sa nandito", + "hashtag.column_settings.tag_mode.any": "Ilan dito", "hashtag.column_settings.tag_mode.none": "Wala dito", + "hashtags.and_other": "…at {count, plural, one {# iba pa} other {# na iba pa}}", "home.column_settings.show_replies": "Ipakita ang mga tugon", "home.pending_critical_update.body": "Mangyaring i-update ang iyong serbiro ng Mastodon sa lalong madaling panahon!", "interaction_modal.login.action": "Iuwi mo ako", @@ -224,6 +225,7 @@ "lists.replies_policy.title": "Ipakita ang mga tugon sa:", "lists.subheading": "Iyong mga talaan", "loading_indicator.label": "Kumakarga…", + "mute_modal.hide_from_notifications": "Itago mula sa mga abiso", "navigation_bar.about": "Tungkol dito", "navigation_bar.blocks": "Nakaharang na mga tagagamit", "navigation_bar.direct": "Mga palihim na banggit", @@ -233,6 +235,7 @@ "navigation_bar.follow_requests": "Mga hiling sa pagsunod", "navigation_bar.follows_and_followers": "Mga sinusundan at tagasunod", "navigation_bar.lists": "Mga listahan", + "navigation_bar.public_timeline": "Pinagsamang timeline", "navigation_bar.search": "Maghanap", "notification.admin.report": "Iniulat ni {name} si {target}", "notification.follow": "Sinundan ka ni {name}", @@ -247,10 +250,12 @@ "notifications.column_settings.alert": "Mga abiso sa Desktop", "notifications.column_settings.favourite": "Mga paborito:", "notifications.column_settings.follow": "Mga bagong tagasunod:", + "notifications.column_settings.poll": "Resulta ng botohan:", "notifications.column_settings.unread_notifications.category": "Hindi Nabasang mga Abiso", "notifications.column_settings.update": "Mga pagbago:", "notifications.filter.all": "Lahat", "notifications.filter.favourites": "Mga paborito", + "notifications.filter.polls": "Resulta ng botohan", "notifications.mark_as_read": "Markahan lahat ng abiso bilang nabasa na", "notifications.policy.filter_not_followers_title": "Mga taong hindi ka susundan", "notifications.policy.filter_not_following_title": "Mga taong hindi mo sinusundan", @@ -294,10 +299,13 @@ "report.thanks.title": "Ayaw mo bang makita ito?", "report.thanks.title_actionable": "Salamat sa pag-uulat, titingnan namin ito.", "report_notification.categories.other": "Iba pa", + "report_notification.categories.violation": "Paglabag sa patakaran", + "report_notification.open": "Buksan ang ulat", "search.quick_action.open_url": "Buksan ang URL sa Mastodon", "search.search_or_paste": "Maghanap o ilagay ang URL", "search_popout.full_text_search_disabled_message": "Hindi magagamit sa {domain}.", "search_popout.full_text_search_logged_out_message": "Magagamit lamang kapag naka-log in.", + "search_popout.recent": "Kamakailang mga paghahanap", "search_results.all": "Lahat", "search_results.see_all": "Ipakita lahat", "server_banner.learn_more": "Matuto nang higit pa", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 32ea6e47c4..e7ab114909 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -90,7 +90,7 @@ "attachments_list.unprocessed": "(neapstrādāti)", "audio.hide": "Slēpt audio", "block_modal.remote_users_caveat": "Mēs vaicāsim serverim {domain} ņemt vērā Tavu lēmumu. Tomēr atbilstība nav nodrošināta, jo atsevišķi serveri var apstrādāt bloķēšanu citādi. Publiski ieraksti joprojām var būt redzami lietotājiem, kuri nav pieteikušies.", - "block_modal.show_less": "Parādīt vairāk", + "block_modal.show_less": "Rādīt mazāk", "block_modal.show_more": "Parādīt mazāk", "boost_modal.combo": "Nospied {combo}, lai nākamreiz šo izlaistu", "bundle_column_error.copy_stacktrace": "Kopēt kļūdu ziņojumu", @@ -309,7 +309,7 @@ "hashtag.counter_by_uses_today": "{count, plural, zero {{counter} ierakstu} one {{counter} ieraksts} other {{counter} ieraksti}} šodien", "hashtag.follow": "Sekot tēmturim", "hashtag.unfollow": "Pārstāt sekot tēmturim", - "hashtags.and_other": "..un {count, plural, other {# vairāk}}", + "hashtags.and_other": "… un {count, plural, other {vēl #}}", "home.column_settings.show_reblogs": "Rādīt pastiprinātos ierakstus", "home.column_settings.show_replies": "Rādīt atbildes", "home.hide_announcements": "Slēpt paziņojumus", From 2c75cf85991bd0c22eaabe4ccd3bfb658ec59d32 Mon Sep 17 00:00:00 2001 From: Michael Stanclift Date: Wed, 22 May 2024 04:05:33 -0500 Subject: [PATCH 221/658] Add "Warning preset" link to admin navigation (#26199) --- config/locales/en-GB.yml | 2 +- config/locales/en.yml | 2 +- config/navigation.rb | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 7e31080dfa..7cd888b373 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -950,7 +950,7 @@ en-GB: delete: Delete edit_preset: Edit warning preset empty: You haven't defined any warning presets yet. - title: Manage warning presets + title: Warning presets webhooks: add_new: Add endpoint delete: Delete diff --git a/config/locales/en.yml b/config/locales/en.yml index d3704bbbcf..43aa8481c6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -951,7 +951,7 @@ en: delete: Delete edit_preset: Edit warning preset empty: You haven't defined any warning presets yet. - title: Manage warning presets + title: Warning presets webhooks: add_new: Add endpoint delete: Delete diff --git a/config/navigation.rb b/config/navigation.rb index efac96d46e..c1dd81501c 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -59,6 +59,7 @@ SimpleNavigation::Configuration.run do |navigation| s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_path, if: -> { current_user.can?(:view_dashboard) } s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), admin_settings_path, if: -> { current_user.can?(:manage_settings) }, highlights_on: %r{/admin/settings} s.item :rules, safe_join([fa_icon('gavel fw'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}, if: -> { current_user.can?(:manage_rules) } + s.item :warning_presets, safe_join([fa_icon('warning fw'), t('admin.warning_presets.title')]), admin_warning_presets_path, highlights_on: %r{/admin/warning_presets}, if: -> { current_user.can?(:manage_settings) } s.item :roles, safe_join([fa_icon('vcard fw'), t('admin.roles.title')]), admin_roles_path, highlights_on: %r{/admin/roles}, if: -> { current_user.can?(:manage_roles) } s.item :announcements, safe_join([fa_icon('bullhorn fw'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}, if: -> { current_user.can?(:manage_announcements) } s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_path, highlights_on: %r{/admin/custom_emojis}, if: -> { current_user.can?(:manage_custom_emojis) } From 2c5ab8f647841ea8075ece50ccc9e12c21af8720 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Wed, 22 May 2024 16:45:18 +0200 Subject: [PATCH 222/658] Remove the access token from Redux & context (#30275) --- .../mastodon/actions/account_notes.ts | 4 +- app/javascript/mastodon/actions/accounts.js | 64 +++++++++---------- .../mastodon/actions/announcements.js | 14 ++-- app/javascript/mastodon/actions/blocks.js | 6 +- app/javascript/mastodon/actions/bookmarks.js | 4 +- app/javascript/mastodon/actions/compose.js | 16 ++--- .../mastodon/actions/conversations.js | 10 +-- .../mastodon/actions/custom_emojis.js | 4 +- app/javascript/mastodon/actions/directory.js | 6 +- .../mastodon/actions/domain_blocks.js | 10 +-- app/javascript/mastodon/actions/favourites.js | 4 +- .../mastodon/actions/featured_tags.js | 2 +- app/javascript/mastodon/actions/filters.js | 12 ++-- app/javascript/mastodon/actions/history.js | 2 +- .../mastodon/actions/interactions.js | 44 ++++++------- app/javascript/mastodon/actions/lists.js | 39 ++++++----- app/javascript/mastodon/actions/markers.ts | 34 +++++----- app/javascript/mastodon/actions/mutes.js | 6 +- .../mastodon/actions/notifications.js | 32 +++++----- .../mastodon/actions/pin_statuses.js | 4 +- app/javascript/mastodon/actions/polls.js | 8 +-- app/javascript/mastodon/actions/reports.js | 4 +- app/javascript/mastodon/actions/search.js | 6 +- app/javascript/mastodon/actions/server.js | 10 +-- app/javascript/mastodon/actions/statuses.js | 22 +++---- .../mastodon/actions/suggestions.js | 8 +-- app/javascript/mastodon/actions/tags.js | 18 +++--- app/javascript/mastodon/actions/timelines.js | 2 +- app/javascript/mastodon/actions/trends.js | 12 ++-- app/javascript/mastodon/api.ts | 22 ++----- app/javascript/mastodon/identity_context.tsx | 4 -- app/javascript/mastodon/initial_state.js | 7 ++ app/javascript/mastodon/reducers/meta.js | 4 +- app/javascript/mastodon/stream.js | 6 +- app/javascript/mastodon/test_helpers.tsx | 1 - 35 files changed, 225 insertions(+), 226 deletions(-) diff --git a/app/javascript/mastodon/actions/account_notes.ts b/app/javascript/mastodon/actions/account_notes.ts index e524e5235b..acd9ecf410 100644 --- a/app/javascript/mastodon/actions/account_notes.ts +++ b/app/javascript/mastodon/actions/account_notes.ts @@ -5,8 +5,8 @@ import api from '../api'; export const submitAccountNote = createAppAsyncThunk( 'account_note/submit', - async (args: { id: string; value: string }, { getState }) => { - const response = await api(getState).post( + async (args: { id: string; value: string }) => { + const response = await api().post( `/api/v1/accounts/${args.id}/note`, { comment: args.value, diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js index 9f3bbba033..cea915e5f1 100644 --- a/app/javascript/mastodon/actions/accounts.js +++ b/app/javascript/mastodon/actions/accounts.js @@ -76,11 +76,11 @@ export const ACCOUNT_REVEAL = 'ACCOUNT_REVEAL'; export * from './accounts_typed'; export function fetchAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchRelationships([id])); dispatch(fetchAccountRequest(id)); - api(getState).get(`/api/v1/accounts/${id}`).then(response => { + api().get(`/api/v1/accounts/${id}`).then(response => { dispatch(importFetchedAccount(response.data)); dispatch(fetchAccountSuccess()); }).catch(error => { @@ -89,10 +89,10 @@ export function fetchAccount(id) { }; } -export const lookupAccount = acct => (dispatch, getState) => { +export const lookupAccount = acct => (dispatch) => { dispatch(lookupAccountRequest(acct)); - api(getState).get('/api/v1/accounts/lookup', { params: { acct } }).then(response => { + api().get('/api/v1/accounts/lookup', { params: { acct } }).then(response => { dispatch(fetchRelationships([response.data.id])); dispatch(importFetchedAccount(response.data)); dispatch(lookupAccountSuccess()); @@ -146,7 +146,7 @@ export function followAccount(id, options = { reblogs: true }) { dispatch(followAccountRequest({ id, locked })); - api(getState).post(`/api/v1/accounts/${id}/follow`, options).then(response => { + api().post(`/api/v1/accounts/${id}/follow`, options).then(response => { dispatch(followAccountSuccess({relationship: response.data, alreadyFollowing})); }).catch(error => { dispatch(followAccountFail({ id, error, locked })); @@ -158,7 +158,7 @@ export function unfollowAccount(id) { return (dispatch, getState) => { dispatch(unfollowAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/unfollow`).then(response => { + api().post(`/api/v1/accounts/${id}/unfollow`).then(response => { dispatch(unfollowAccountSuccess({relationship: response.data, statuses: getState().get('statuses')})); }).catch(error => { dispatch(unfollowAccountFail({ id, error })); @@ -170,7 +170,7 @@ export function blockAccount(id) { return (dispatch, getState) => { dispatch(blockAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/block`).then(response => { + api().post(`/api/v1/accounts/${id}/block`).then(response => { // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers dispatch(blockAccountSuccess({ relationship: response.data, statuses: getState().get('statuses') })); }).catch(error => { @@ -180,10 +180,10 @@ export function blockAccount(id) { } export function unblockAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unblockAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/unblock`).then(response => { + api().post(`/api/v1/accounts/${id}/unblock`).then(response => { dispatch(unblockAccountSuccess({ relationship: response.data })); }).catch(error => { dispatch(unblockAccountFail({ id, error })); @@ -223,7 +223,7 @@ export function muteAccount(id, notifications, duration=0) { return (dispatch, getState) => { dispatch(muteAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications, duration }).then(response => { + api().post(`/api/v1/accounts/${id}/mute`, { notifications, duration }).then(response => { // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers dispatch(muteAccountSuccess({ relationship: response.data, statuses: getState().get('statuses') })); }).catch(error => { @@ -233,10 +233,10 @@ export function muteAccount(id, notifications, duration=0) { } export function unmuteAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unmuteAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/unmute`).then(response => { + api().post(`/api/v1/accounts/${id}/unmute`).then(response => { dispatch(unmuteAccountSuccess({ relationship: response.data })); }).catch(error => { dispatch(unmuteAccountFail({ id, error })); @@ -274,10 +274,10 @@ export function unmuteAccountFail(error) { export function fetchFollowers(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchFollowersRequest(id)); - api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => { + api().get(`/api/v1/accounts/${id}/followers`).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -324,7 +324,7 @@ export function expandFollowers(id) { dispatch(expandFollowersRequest(id)); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -361,10 +361,10 @@ export function expandFollowersFail(id, error) { } export function fetchFollowing(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchFollowingRequest(id)); - api(getState).get(`/api/v1/accounts/${id}/following`).then(response => { + api().get(`/api/v1/accounts/${id}/following`).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -411,7 +411,7 @@ export function expandFollowing(id) { dispatch(expandFollowingRequest(id)); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -460,7 +460,7 @@ export function fetchRelationships(accountIds) { dispatch(fetchRelationshipsRequest(newAccountIds)); - api(getState).get(`/api/v1/accounts/relationships?with_suspended=true&${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => { + api().get(`/api/v1/accounts/relationships?with_suspended=true&${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => { dispatch(fetchRelationshipsSuccess({ relationships: response.data })); }).catch(error => { dispatch(fetchRelationshipsFail(error)); @@ -486,10 +486,10 @@ export function fetchRelationshipsFail(error) { } export function fetchFollowRequests() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchFollowRequestsRequest()); - api(getState).get('/api/v1/follow_requests').then(response => { + api().get('/api/v1/follow_requests').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null)); @@ -528,7 +528,7 @@ export function expandFollowRequests() { dispatch(expandFollowRequestsRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null)); @@ -558,10 +558,10 @@ export function expandFollowRequestsFail(error) { } export function authorizeFollowRequest(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(authorizeFollowRequestRequest(id)); - api(getState) + api() .post(`/api/v1/follow_requests/${id}/authorize`) .then(() => dispatch(authorizeFollowRequestSuccess({ id }))) .catch(error => dispatch(authorizeFollowRequestFail(id, error))); @@ -585,10 +585,10 @@ export function authorizeFollowRequestFail(id, error) { export function rejectFollowRequest(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(rejectFollowRequestRequest(id)); - api(getState) + api() .post(`/api/v1/follow_requests/${id}/reject`) .then(() => dispatch(rejectFollowRequestSuccess({ id }))) .catch(error => dispatch(rejectFollowRequestFail(id, error))); @@ -611,10 +611,10 @@ export function rejectFollowRequestFail(id, error) { } export function pinAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(pinAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/pin`).then(response => { + api().post(`/api/v1/accounts/${id}/pin`).then(response => { dispatch(pinAccountSuccess({ relationship: response.data })); }).catch(error => { dispatch(pinAccountFail(error)); @@ -623,10 +623,10 @@ export function pinAccount(id) { } export function unpinAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unpinAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/unpin`).then(response => { + api().post(`/api/v1/accounts/${id}/unpin`).then(response => { dispatch(unpinAccountSuccess({ relationship: response.data })); }).catch(error => { dispatch(unpinAccountFail(error)); @@ -662,7 +662,7 @@ export function unpinAccountFail(error) { }; } -export const updateAccount = ({ displayName, note, avatar, header, discoverable, indexable }) => (dispatch, getState) => { +export const updateAccount = ({ displayName, note, avatar, header, discoverable, indexable }) => (dispatch) => { const data = new FormData(); data.append('display_name', displayName); @@ -672,7 +672,7 @@ export const updateAccount = ({ displayName, note, avatar, header, discoverable, data.append('discoverable', discoverable); data.append('indexable', indexable); - return api(getState).patch('/api/v1/accounts/update_credentials', data).then(response => { + return api().patch('/api/v1/accounts/update_credentials', data).then(response => { dispatch(importFetchedAccount(response.data)); }); }; diff --git a/app/javascript/mastodon/actions/announcements.js b/app/javascript/mastodon/actions/announcements.js index 339c5f3adc..7657b05dc4 100644 --- a/app/javascript/mastodon/actions/announcements.js +++ b/app/javascript/mastodon/actions/announcements.js @@ -26,10 +26,10 @@ export const ANNOUNCEMENTS_TOGGLE_SHOW = 'ANNOUNCEMENTS_TOGGLE_SHOW'; const noOp = () => {}; -export const fetchAnnouncements = (done = noOp) => (dispatch, getState) => { +export const fetchAnnouncements = (done = noOp) => (dispatch) => { dispatch(fetchAnnouncementsRequest()); - api(getState).get('/api/v1/announcements').then(response => { + api().get('/api/v1/announcements').then(response => { dispatch(fetchAnnouncementsSuccess(response.data.map(x => normalizeAnnouncement(x)))); }).catch(error => { dispatch(fetchAnnouncementsFail(error)); @@ -61,10 +61,10 @@ export const updateAnnouncements = announcement => ({ announcement: normalizeAnnouncement(announcement), }); -export const dismissAnnouncement = announcementId => (dispatch, getState) => { +export const dismissAnnouncement = announcementId => (dispatch) => { dispatch(dismissAnnouncementRequest(announcementId)); - api(getState).post(`/api/v1/announcements/${announcementId}/dismiss`).then(() => { + api().post(`/api/v1/announcements/${announcementId}/dismiss`).then(() => { dispatch(dismissAnnouncementSuccess(announcementId)); }).catch(error => { dispatch(dismissAnnouncementFail(announcementId, error)); @@ -103,7 +103,7 @@ export const addReaction = (announcementId, name) => (dispatch, getState) => { dispatch(addReactionRequest(announcementId, name, alreadyAdded)); } - api(getState).put(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => { + api().put(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => { dispatch(addReactionSuccess(announcementId, name, alreadyAdded)); }).catch(err => { if (!alreadyAdded) { @@ -134,10 +134,10 @@ export const addReactionFail = (announcementId, name, error) => ({ skipLoading: true, }); -export const removeReaction = (announcementId, name) => (dispatch, getState) => { +export const removeReaction = (announcementId, name) => (dispatch) => { dispatch(removeReactionRequest(announcementId, name)); - api(getState).delete(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => { + api().delete(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => { dispatch(removeReactionSuccess(announcementId, name)); }).catch(err => { dispatch(removeReactionFail(announcementId, name, err)); diff --git a/app/javascript/mastodon/actions/blocks.js b/app/javascript/mastodon/actions/blocks.js index 54296d0905..5c66e27bec 100644 --- a/app/javascript/mastodon/actions/blocks.js +++ b/app/javascript/mastodon/actions/blocks.js @@ -13,10 +13,10 @@ export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS'; export const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL'; export function fetchBlocks() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchBlocksRequest()); - api(getState).get('/api/v1/blocks').then(response => { + api().get('/api/v1/blocks').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null)); @@ -56,7 +56,7 @@ export function expandBlocks() { dispatch(expandBlocksRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(expandBlocksSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/mastodon/actions/bookmarks.js b/app/javascript/mastodon/actions/bookmarks.js index 0b16f61e63..89716b224c 100644 --- a/app/javascript/mastodon/actions/bookmarks.js +++ b/app/javascript/mastodon/actions/bookmarks.js @@ -18,7 +18,7 @@ export function fetchBookmarkedStatuses() { dispatch(fetchBookmarkedStatusesRequest()); - api(getState).get('/api/v1/bookmarks').then(response => { + api().get('/api/v1/bookmarks').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(fetchBookmarkedStatusesSuccess(response.data, next ? next.uri : null)); @@ -59,7 +59,7 @@ export function expandBookmarkedStatuses() { dispatch(expandBookmarkedStatusesRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(expandBookmarkedStatusesSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 7477e45e5e..b07dff182a 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -196,7 +196,7 @@ export function submitCompose(routerHistory) { }); } - api(getState).request({ + api().request({ url: statusId === null ? '/api/v1/statuses' : `/api/v1/statuses/${statusId}`, method: statusId === null ? 'post' : 'put', data: { @@ -304,7 +304,7 @@ export function uploadCompose(files) { const data = new FormData(); data.append('file', file); - api(getState).post('/api/v2/media', data, { + api().post('/api/v2/media', data, { onUploadProgress: function({ loaded }){ progress[i] = loaded; dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total)); @@ -321,7 +321,7 @@ export function uploadCompose(files) { let tryCount = 1; const poll = () => { - api(getState).get(`/api/v1/media/${data.id}`).then(response => { + api().get(`/api/v1/media/${data.id}`).then(response => { if (response.status === 200) { dispatch(uploadComposeSuccess(response.data, file)); } else if (response.status === 206) { @@ -343,7 +343,7 @@ export const uploadComposeProcessing = () => ({ type: COMPOSE_UPLOAD_PROCESSING, }); -export const uploadThumbnail = (id, file) => (dispatch, getState) => { +export const uploadThumbnail = (id, file) => (dispatch) => { dispatch(uploadThumbnailRequest()); const total = file.size; @@ -351,7 +351,7 @@ export const uploadThumbnail = (id, file) => (dispatch, getState) => { data.append('thumbnail', file); - api(getState).put(`/api/v1/media/${id}`, data, { + api().put(`/api/v1/media/${id}`, data, { onUploadProgress: ({ loaded }) => { dispatch(uploadThumbnailProgress(loaded, total)); }, @@ -434,7 +434,7 @@ export function changeUploadCompose(id, params) { dispatch(changeUploadComposeSuccess(data, true)); } else { - api(getState).put(`/api/v1/media/${id}`, params).then(response => { + api().put(`/api/v1/media/${id}`, params).then(response => { dispatch(changeUploadComposeSuccess(response.data, false)); }).catch(error => { dispatch(changeUploadComposeFail(id, error)); @@ -522,7 +522,7 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => fetchComposeSuggestionsAccountsController = new AbortController(); - api(getState).get('/api/v1/accounts/search', { + api().get('/api/v1/accounts/search', { signal: fetchComposeSuggestionsAccountsController.signal, params: { @@ -556,7 +556,7 @@ const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => { fetchComposeSuggestionsTagsController = new AbortController(); - api(getState).get('/api/v2/search', { + api().get('/api/v2/search', { signal: fetchComposeSuggestionsTagsController.signal, params: { diff --git a/app/javascript/mastodon/actions/conversations.js b/app/javascript/mastodon/actions/conversations.js index 8c4c4529fb..03174c485d 100644 --- a/app/javascript/mastodon/actions/conversations.js +++ b/app/javascript/mastodon/actions/conversations.js @@ -28,13 +28,13 @@ export const unmountConversations = () => ({ type: CONVERSATIONS_UNMOUNT, }); -export const markConversationRead = conversationId => (dispatch, getState) => { +export const markConversationRead = conversationId => (dispatch) => { dispatch({ type: CONVERSATIONS_READ, id: conversationId, }); - api(getState).post(`/api/v1/conversations/${conversationId}/read`); + api().post(`/api/v1/conversations/${conversationId}/read`); }; export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => { @@ -48,7 +48,7 @@ export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => { const isLoadingRecent = !!params.since_id; - api(getState).get('/api/v1/conversations', { params }) + api().get('/api/v1/conversations', { params }) .then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); @@ -88,10 +88,10 @@ export const updateConversations = conversation => dispatch => { }); }; -export const deleteConversation = conversationId => (dispatch, getState) => { +export const deleteConversation = conversationId => (dispatch) => { dispatch(deleteConversationRequest(conversationId)); - api(getState).delete(`/api/v1/conversations/${conversationId}`) + api().delete(`/api/v1/conversations/${conversationId}`) .then(() => dispatch(deleteConversationSuccess(conversationId))) .catch(error => dispatch(deleteConversationFail(conversationId, error))); }; diff --git a/app/javascript/mastodon/actions/custom_emojis.js b/app/javascript/mastodon/actions/custom_emojis.js index 9ec8156b17..fb65f072dc 100644 --- a/app/javascript/mastodon/actions/custom_emojis.js +++ b/app/javascript/mastodon/actions/custom_emojis.js @@ -5,10 +5,10 @@ export const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS'; export const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL'; export function fetchCustomEmojis() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchCustomEmojisRequest()); - api(getState).get('/api/v1/custom_emojis').then(response => { + api().get('/api/v1/custom_emojis').then(response => { dispatch(fetchCustomEmojisSuccess(response.data)); }).catch(error => { dispatch(fetchCustomEmojisFail(error)); diff --git a/app/javascript/mastodon/actions/directory.js b/app/javascript/mastodon/actions/directory.js index cda63f2b5a..7a0748029d 100644 --- a/app/javascript/mastodon/actions/directory.js +++ b/app/javascript/mastodon/actions/directory.js @@ -11,10 +11,10 @@ export const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST'; export const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS'; export const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL'; -export const fetchDirectory = params => (dispatch, getState) => { +export const fetchDirectory = params => (dispatch) => { dispatch(fetchDirectoryRequest()); - api(getState).get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => { + api().get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(fetchDirectorySuccess(data)); dispatch(fetchRelationships(data.map(x => x.id))); @@ -40,7 +40,7 @@ export const expandDirectory = params => (dispatch, getState) => { const loadedItems = getState().getIn(['user_lists', 'directory', 'items']).size; - api(getState).get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => { + api().get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(expandDirectorySuccess(data)); dispatch(fetchRelationships(data.map(x => x.id))); diff --git a/app/javascript/mastodon/actions/domain_blocks.js b/app/javascript/mastodon/actions/domain_blocks.js index 55c0a6ce9d..727f800af3 100644 --- a/app/javascript/mastodon/actions/domain_blocks.js +++ b/app/javascript/mastodon/actions/domain_blocks.js @@ -24,7 +24,7 @@ export function blockDomain(domain) { return (dispatch, getState) => { dispatch(blockDomainRequest(domain)); - api(getState).post('/api/v1/domain_blocks', { domain }).then(() => { + api().post('/api/v1/domain_blocks', { domain }).then(() => { const at_domain = '@' + domain; const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id')); @@ -54,7 +54,7 @@ export function unblockDomain(domain) { return (dispatch, getState) => { dispatch(unblockDomainRequest(domain)); - api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(() => { + api().delete('/api/v1/domain_blocks', { params: { domain } }).then(() => { const at_domain = '@' + domain; const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id')); dispatch(unblockDomainSuccess({ domain, accounts })); @@ -80,10 +80,10 @@ export function unblockDomainFail(domain, error) { } export function fetchDomainBlocks() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchDomainBlocksRequest()); - api(getState).get('/api/v1/domain_blocks').then(response => { + api().get('/api/v1/domain_blocks').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null)); }).catch(err => { @@ -123,7 +123,7 @@ export function expandDomainBlocks() { dispatch(expandDomainBlocksRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null)); }).catch(err => { diff --git a/app/javascript/mastodon/actions/favourites.js b/app/javascript/mastodon/actions/favourites.js index 2d4d4e6206..ff475c82be 100644 --- a/app/javascript/mastodon/actions/favourites.js +++ b/app/javascript/mastodon/actions/favourites.js @@ -18,7 +18,7 @@ export function fetchFavouritedStatuses() { dispatch(fetchFavouritedStatusesRequest()); - api(getState).get('/api/v1/favourites').then(response => { + api().get('/api/v1/favourites').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null)); @@ -62,7 +62,7 @@ export function expandFavouritedStatuses() { dispatch(expandFavouritedStatusesRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/mastodon/actions/featured_tags.js b/app/javascript/mastodon/actions/featured_tags.js index 18bb615394..6ee4dee2bc 100644 --- a/app/javascript/mastodon/actions/featured_tags.js +++ b/app/javascript/mastodon/actions/featured_tags.js @@ -11,7 +11,7 @@ export const fetchFeaturedTags = (id) => (dispatch, getState) => { dispatch(fetchFeaturedTagsRequest(id)); - api(getState).get(`/api/v1/accounts/${id}/featured_tags`) + api().get(`/api/v1/accounts/${id}/featured_tags`) .then(({ data }) => dispatch(fetchFeaturedTagsSuccess(id, data))) .catch(err => dispatch(fetchFeaturedTagsFail(id, err))); }; diff --git a/app/javascript/mastodon/actions/filters.js b/app/javascript/mastodon/actions/filters.js index a11956ac56..588e390f0a 100644 --- a/app/javascript/mastodon/actions/filters.js +++ b/app/javascript/mastodon/actions/filters.js @@ -23,13 +23,13 @@ export const initAddFilter = (status, { contextType }) => dispatch => }, })); -export const fetchFilters = () => (dispatch, getState) => { +export const fetchFilters = () => (dispatch) => { dispatch({ type: FILTERS_FETCH_REQUEST, skipLoading: true, }); - api(getState) + api() .get('/api/v2/filters') .then(({ data }) => dispatch({ type: FILTERS_FETCH_SUCCESS, @@ -44,10 +44,10 @@ export const fetchFilters = () => (dispatch, getState) => { })); }; -export const createFilterStatus = (params, onSuccess, onFail) => (dispatch, getState) => { +export const createFilterStatus = (params, onSuccess, onFail) => (dispatch) => { dispatch(createFilterStatusRequest()); - api(getState).post(`/api/v2/filters/${params.filter_id}/statuses`, params).then(response => { + api().post(`/api/v2/filters/${params.filter_id}/statuses`, params).then(response => { dispatch(createFilterStatusSuccess(response.data)); if (onSuccess) onSuccess(); }).catch(error => { @@ -70,10 +70,10 @@ export const createFilterStatusFail = error => ({ error, }); -export const createFilter = (params, onSuccess, onFail) => (dispatch, getState) => { +export const createFilter = (params, onSuccess, onFail) => (dispatch) => { dispatch(createFilterRequest()); - api(getState).post('/api/v2/filters', params).then(response => { + api().post('/api/v2/filters', params).then(response => { dispatch(createFilterSuccess(response.data)); if (onSuccess) onSuccess(response.data); }).catch(error => { diff --git a/app/javascript/mastodon/actions/history.js b/app/javascript/mastodon/actions/history.js index 52401b7dce..07732ea187 100644 --- a/app/javascript/mastodon/actions/history.js +++ b/app/javascript/mastodon/actions/history.js @@ -15,7 +15,7 @@ export const fetchHistory = statusId => (dispatch, getState) => { dispatch(fetchHistoryRequest(statusId)); - api(getState).get(`/api/v1/statuses/${statusId}/history`).then(({ data }) => { + api().get(`/api/v1/statuses/${statusId}/history`).then(({ data }) => { dispatch(importFetchedAccounts(data.map(x => x.account))); dispatch(fetchHistorySuccess(statusId, data)); }).catch(error => dispatch(fetchHistoryFail(error))); diff --git a/app/javascript/mastodon/actions/interactions.js b/app/javascript/mastodon/actions/interactions.js index 7d0144438a..fe7c911b61 100644 --- a/app/javascript/mastodon/actions/interactions.js +++ b/app/javascript/mastodon/actions/interactions.js @@ -52,10 +52,10 @@ export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS'; export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL'; export function reblog(status, visibility) { - return function (dispatch, getState) { + return function (dispatch) { dispatch(reblogRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) { + api().post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) { // The reblog API method returns a new status wrapped around the original. In this case we are only // interested in how the original is modified, hence passing it skipping the wrapper dispatch(importFetchedStatus(response.data.reblog)); @@ -67,10 +67,10 @@ export function reblog(status, visibility) { } export function unreblog(status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unreblogRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unreblogSuccess(status)); }).catch(error => { @@ -130,10 +130,10 @@ export function unreblogFail(status, error) { } export function favourite(status) { - return function (dispatch, getState) { + return function (dispatch) { dispatch(favouriteRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) { + api().post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) { dispatch(importFetchedStatus(response.data)); dispatch(favouriteSuccess(status)); }).catch(function (error) { @@ -143,10 +143,10 @@ export function favourite(status) { } export function unfavourite(status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unfavouriteRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unfavouriteSuccess(status)); }).catch(error => { @@ -206,10 +206,10 @@ export function unfavouriteFail(status, error) { } export function bookmark(status) { - return function (dispatch, getState) { + return function (dispatch) { dispatch(bookmarkRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function (response) { + api().post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function (response) { dispatch(importFetchedStatus(response.data)); dispatch(bookmarkSuccess(status, response.data)); }).catch(function (error) { @@ -219,10 +219,10 @@ export function bookmark(status) { } export function unbookmark(status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unbookmarkRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unbookmarkSuccess(status, response.data)); }).catch(error => { @@ -278,10 +278,10 @@ export function unbookmarkFail(status, error) { } export function fetchReblogs(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchReblogsRequest(id)); - api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => { + api().get(`/api/v1/statuses/${id}/reblogged_by`).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchReblogsSuccess(id, response.data, next ? next.uri : null)); @@ -325,7 +325,7 @@ export function expandReblogs(id) { dispatch(expandReblogsRequest(id)); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -360,10 +360,10 @@ export function expandReblogsFail(id, error) { } export function fetchFavourites(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchFavouritesRequest(id)); - api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => { + api().get(`/api/v1/statuses/${id}/favourited_by`).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchFavouritesSuccess(id, response.data, next ? next.uri : null)); @@ -407,7 +407,7 @@ export function expandFavourites(id) { dispatch(expandFavouritesRequest(id)); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -442,10 +442,10 @@ export function expandFavouritesFail(id, error) { } export function pin(status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(pinRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(pinSuccess(status)); }).catch(error => { @@ -480,10 +480,10 @@ export function pinFail(status, error) { } export function unpin (status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unpinRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unpinSuccess(status)); }).catch(error => { diff --git a/app/javascript/mastodon/actions/lists.js b/app/javascript/mastodon/actions/lists.js index b0789cd426..9956059387 100644 --- a/app/javascript/mastodon/actions/lists.js +++ b/app/javascript/mastodon/actions/lists.js @@ -57,7 +57,7 @@ export const fetchList = id => (dispatch, getState) => { dispatch(fetchListRequest(id)); - api(getState).get(`/api/v1/lists/${id}`) + api().get(`/api/v1/lists/${id}`) .then(({ data }) => dispatch(fetchListSuccess(data))) .catch(err => dispatch(fetchListFail(id, err))); }; @@ -78,10 +78,10 @@ export const fetchListFail = (id, error) => ({ error, }); -export const fetchLists = () => (dispatch, getState) => { +export const fetchLists = () => (dispatch) => { dispatch(fetchListsRequest()); - api(getState).get('/api/v1/lists') + api().get('/api/v1/lists') .then(({ data }) => dispatch(fetchListsSuccess(data))) .catch(err => dispatch(fetchListsFail(err))); }; @@ -125,10 +125,10 @@ export const changeListEditorTitle = value => ({ value, }); -export const createList = (title, shouldReset) => (dispatch, getState) => { +export const createList = (title, shouldReset) => (dispatch) => { dispatch(createListRequest()); - api(getState).post('/api/v1/lists', { title }).then(({ data }) => { + api().post('/api/v1/lists', { title }).then(({ data }) => { dispatch(createListSuccess(data)); if (shouldReset) { @@ -151,10 +151,10 @@ export const createListFail = error => ({ error, }); -export const updateList = (id, title, shouldReset, isExclusive, replies_policy) => (dispatch, getState) => { +export const updateList = (id, title, shouldReset, isExclusive, replies_policy) => (dispatch) => { dispatch(updateListRequest(id)); - api(getState).put(`/api/v1/lists/${id}`, { title, replies_policy, exclusive: typeof isExclusive === 'undefined' ? undefined : !!isExclusive }).then(({ data }) => { + api().put(`/api/v1/lists/${id}`, { title, replies_policy, exclusive: typeof isExclusive === 'undefined' ? undefined : !!isExclusive }).then(({ data }) => { dispatch(updateListSuccess(data)); if (shouldReset) { @@ -183,10 +183,10 @@ export const resetListEditor = () => ({ type: LIST_EDITOR_RESET, }); -export const deleteList = id => (dispatch, getState) => { +export const deleteList = id => (dispatch) => { dispatch(deleteListRequest(id)); - api(getState).delete(`/api/v1/lists/${id}`) + api().delete(`/api/v1/lists/${id}`) .then(() => dispatch(deleteListSuccess(id))) .catch(err => dispatch(deleteListFail(id, err))); }; @@ -207,10 +207,10 @@ export const deleteListFail = (id, error) => ({ error, }); -export const fetchListAccounts = listId => (dispatch, getState) => { +export const fetchListAccounts = listId => (dispatch) => { dispatch(fetchListAccountsRequest(listId)); - api(getState).get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => { + api().get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(fetchListAccountsSuccess(listId, data)); }).catch(err => dispatch(fetchListAccountsFail(listId, err))); @@ -234,7 +234,7 @@ export const fetchListAccountsFail = (id, error) => ({ error, }); -export const fetchListSuggestions = q => (dispatch, getState) => { +export const fetchListSuggestions = q => (dispatch) => { const params = { q, resolve: false, @@ -242,7 +242,7 @@ export const fetchListSuggestions = q => (dispatch, getState) => { following: true, }; - api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => { + api().get('/api/v1/accounts/search', { params }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(fetchListSuggestionsReady(q, data)); }).catch(error => dispatch(showAlertForError(error))); @@ -267,10 +267,10 @@ export const addToListEditor = accountId => (dispatch, getState) => { dispatch(addToList(getState().getIn(['listEditor', 'listId']), accountId)); }; -export const addToList = (listId, accountId) => (dispatch, getState) => { +export const addToList = (listId, accountId) => (dispatch) => { dispatch(addToListRequest(listId, accountId)); - api(getState).post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] }) + api().post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] }) .then(() => dispatch(addToListSuccess(listId, accountId))) .catch(err => dispatch(addToListFail(listId, accountId, err))); }; @@ -298,10 +298,10 @@ export const removeFromListEditor = accountId => (dispatch, getState) => { dispatch(removeFromList(getState().getIn(['listEditor', 'listId']), accountId)); }; -export const removeFromList = (listId, accountId) => (dispatch, getState) => { +export const removeFromList = (listId, accountId) => (dispatch) => { dispatch(removeFromListRequest(listId, accountId)); - api(getState).delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } }) + api().delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } }) .then(() => dispatch(removeFromListSuccess(listId, accountId))) .catch(err => dispatch(removeFromListFail(listId, accountId, err))); }; @@ -338,10 +338,10 @@ export const setupListAdder = accountId => (dispatch, getState) => { dispatch(fetchAccountLists(accountId)); }; -export const fetchAccountLists = accountId => (dispatch, getState) => { +export const fetchAccountLists = accountId => (dispatch) => { dispatch(fetchAccountListsRequest(accountId)); - api(getState).get(`/api/v1/accounts/${accountId}/lists`) + api().get(`/api/v1/accounts/${accountId}/lists`) .then(({ data }) => dispatch(fetchAccountListsSuccess(accountId, data))) .catch(err => dispatch(fetchAccountListsFail(accountId, err))); }; @@ -370,4 +370,3 @@ export const addToListAdder = listId => (dispatch, getState) => { export const removeFromListAdder = listId => (dispatch, getState) => { dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId']))); }; - diff --git a/app/javascript/mastodon/actions/markers.ts b/app/javascript/mastodon/actions/markers.ts index 91f78ee286..03f577c540 100644 --- a/app/javascript/mastodon/actions/markers.ts +++ b/app/javascript/mastodon/actions/markers.ts @@ -1,19 +1,24 @@ import { debounce } from 'lodash'; import type { MarkerJSON } from 'mastodon/api_types/markers'; +import { getAccessToken } from 'mastodon/initial_state'; import type { AppDispatch, RootState } from 'mastodon/store'; import { createAppAsyncThunk } from 'mastodon/store/typed_functions'; -import api, { authorizationTokenFromState } from '../api'; +import api from '../api'; import { compareId } from '../compare_id'; export const synchronouslySubmitMarkers = createAppAsyncThunk( 'markers/submit', async (_args, { getState }) => { - const accessToken = authorizationTokenFromState(getState); + const accessToken = getAccessToken(); const params = buildPostMarkersParams(getState()); - if (Object.keys(params).length === 0 || !accessToken) { + if ( + Object.keys(params).length === 0 || + !accessToken || + accessToken === '' + ) { return; } @@ -96,14 +101,14 @@ export const submitMarkersAction = createAppAsyncThunk<{ home: string | undefined; notifications: string | undefined; }>('markers/submitAction', async (_args, { getState }) => { - const accessToken = authorizationTokenFromState(getState); + const accessToken = getAccessToken(); const params = buildPostMarkersParams(getState()); - if (Object.keys(params).length === 0 || accessToken === '') { + if (Object.keys(params).length === 0 || !accessToken || accessToken === '') { return { home: undefined, notifications: undefined }; } - await api(getState).post('/api/v1/markers', params); + await api().post('/api/v1/markers', params); return { home: params.home?.last_read_id, @@ -133,14 +138,11 @@ export const submitMarkers = createAppAsyncThunk( }, ); -export const fetchMarkers = createAppAsyncThunk( - 'markers/fetch', - async (_args, { getState }) => { - const response = await api(getState).get>( - `/api/v1/markers`, - { params: { timeline: ['notifications'] } }, - ); +export const fetchMarkers = createAppAsyncThunk('markers/fetch', async () => { + const response = await api().get>( + `/api/v1/markers`, + { params: { timeline: ['notifications'] } }, + ); - return { markers: response.data }; - }, -); + return { markers: response.data }; +}); diff --git a/app/javascript/mastodon/actions/mutes.js b/app/javascript/mastodon/actions/mutes.js index 99c113f414..3676748cf3 100644 --- a/app/javascript/mastodon/actions/mutes.js +++ b/app/javascript/mastodon/actions/mutes.js @@ -13,10 +13,10 @@ export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS'; export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL'; export function fetchMutes() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchMutesRequest()); - api(getState).get('/api/v1/mutes').then(response => { + api().get('/api/v1/mutes').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchMutesSuccess(response.data, next ? next.uri : null)); @@ -56,7 +56,7 @@ export function expandMutes() { dispatch(expandMutesRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(expandMutesSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js index b54cbe27b9..fe728aa26e 100644 --- a/app/javascript/mastodon/actions/notifications.js +++ b/app/javascript/mastodon/actions/notifications.js @@ -216,7 +216,7 @@ export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) { dispatch(expandNotificationsRequest(isLoadingMore)); - api(getState).get('/api/v1/notifications', { params, signal: expandNotificationsController.signal }).then(response => { + api().get('/api/v1/notifications', { params, signal: expandNotificationsController.signal }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(item => item.account))); @@ -262,12 +262,12 @@ export function expandNotificationsFail(error, isLoadingMore) { } export function clearNotifications() { - return (dispatch, getState) => { + return (dispatch) => { dispatch({ type: NOTIFICATIONS_CLEAR, }); - api(getState).post('/api/v1/notifications/clear'); + api().post('/api/v1/notifications/clear'); }; } @@ -346,10 +346,10 @@ export function setBrowserPermission (value) { }; } -export const fetchNotificationPolicy = () => (dispatch, getState) => { +export const fetchNotificationPolicy = () => (dispatch) => { dispatch(fetchNotificationPolicyRequest()); - api(getState).get('/api/v1/notifications/policy').then(({ data }) => { + api().get('/api/v1/notifications/policy').then(({ data }) => { dispatch(fetchNotificationPolicySuccess(data)); }).catch(err => { dispatch(fetchNotificationPolicyFail(err)); @@ -370,10 +370,10 @@ export const fetchNotificationPolicyFail = error => ({ error, }); -export const updateNotificationsPolicy = params => (dispatch, getState) => { +export const updateNotificationsPolicy = params => (dispatch) => { dispatch(fetchNotificationPolicyRequest()); - api(getState).put('/api/v1/notifications/policy', params).then(({ data }) => { + api().put('/api/v1/notifications/policy', params).then(({ data }) => { dispatch(fetchNotificationPolicySuccess(data)); }).catch(err => { dispatch(fetchNotificationPolicyFail(err)); @@ -393,7 +393,7 @@ export const fetchNotificationRequests = () => (dispatch, getState) => { dispatch(fetchNotificationRequestsRequest()); - api(getState).get('/api/v1/notifications/requests', { params }).then(response => { + api().get('/api/v1/notifications/requests', { params }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(x => x.account))); dispatch(fetchNotificationRequestsSuccess(response.data, next ? next.uri : null)); @@ -426,7 +426,7 @@ export const expandNotificationRequests = () => (dispatch, getState) => { dispatch(expandNotificationRequestsRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(x => x.account))); dispatch(expandNotificationRequestsSuccess(response.data, next?.uri)); @@ -459,7 +459,7 @@ export const fetchNotificationRequest = id => (dispatch, getState) => { dispatch(fetchNotificationRequestRequest(id)); - api(getState).get(`/api/v1/notifications/requests/${id}`).then(({ data }) => { + api().get(`/api/v1/notifications/requests/${id}`).then(({ data }) => { dispatch(fetchNotificationRequestSuccess(data)); }).catch(err => { dispatch(fetchNotificationRequestFail(id, err)); @@ -482,10 +482,10 @@ export const fetchNotificationRequestFail = (id, error) => ({ error, }); -export const acceptNotificationRequest = id => (dispatch, getState) => { +export const acceptNotificationRequest = id => (dispatch) => { dispatch(acceptNotificationRequestRequest(id)); - api(getState).post(`/api/v1/notifications/requests/${id}/accept`).then(() => { + api().post(`/api/v1/notifications/requests/${id}/accept`).then(() => { dispatch(acceptNotificationRequestSuccess(id)); }).catch(err => { dispatch(acceptNotificationRequestFail(id, err)); @@ -508,10 +508,10 @@ export const acceptNotificationRequestFail = (id, error) => ({ error, }); -export const dismissNotificationRequest = id => (dispatch, getState) => { +export const dismissNotificationRequest = id => (dispatch) => { dispatch(dismissNotificationRequestRequest(id)); - api(getState).post(`/api/v1/notifications/requests/${id}/dismiss`).then(() =>{ + api().post(`/api/v1/notifications/requests/${id}/dismiss`).then(() =>{ dispatch(dismissNotificationRequestSuccess(id)); }).catch(err => { dispatch(dismissNotificationRequestFail(id, err)); @@ -550,7 +550,7 @@ export const fetchNotificationsForRequest = accountId => (dispatch, getState) => dispatch(fetchNotificationsForRequestRequest()); - api(getState).get('/api/v1/notifications', { params }).then(response => { + api().get('/api/v1/notifications', { params }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(item => item.account))); dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status))); @@ -586,7 +586,7 @@ export const expandNotificationsForRequest = () => (dispatch, getState) => { dispatch(expandNotificationsForRequestRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(item => item.account))); dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status))); diff --git a/app/javascript/mastodon/actions/pin_statuses.js b/app/javascript/mastodon/actions/pin_statuses.js index baa10d1562..d583eab573 100644 --- a/app/javascript/mastodon/actions/pin_statuses.js +++ b/app/javascript/mastodon/actions/pin_statuses.js @@ -8,10 +8,10 @@ export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS'; export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL'; export function fetchPinnedStatuses() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchPinnedStatusesRequest()); - api(getState).get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => { + api().get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => { dispatch(importFetchedStatuses(response.data)); dispatch(fetchPinnedStatusesSuccess(response.data, null)); }).catch(error => { diff --git a/app/javascript/mastodon/actions/polls.js b/app/javascript/mastodon/actions/polls.js index a37410dc90..aa49341444 100644 --- a/app/javascript/mastodon/actions/polls.js +++ b/app/javascript/mastodon/actions/polls.js @@ -10,10 +10,10 @@ export const POLL_FETCH_REQUEST = 'POLL_FETCH_REQUEST'; export const POLL_FETCH_SUCCESS = 'POLL_FETCH_SUCCESS'; export const POLL_FETCH_FAIL = 'POLL_FETCH_FAIL'; -export const vote = (pollId, choices) => (dispatch, getState) => { +export const vote = (pollId, choices) => (dispatch) => { dispatch(voteRequest()); - api(getState).post(`/api/v1/polls/${pollId}/votes`, { choices }) + api().post(`/api/v1/polls/${pollId}/votes`, { choices }) .then(({ data }) => { dispatch(importFetchedPoll(data)); dispatch(voteSuccess(data)); @@ -21,10 +21,10 @@ export const vote = (pollId, choices) => (dispatch, getState) => { .catch(err => dispatch(voteFail(err))); }; -export const fetchPoll = pollId => (dispatch, getState) => { +export const fetchPoll = pollId => (dispatch) => { dispatch(fetchPollRequest()); - api(getState).get(`/api/v1/polls/${pollId}`) + api().get(`/api/v1/polls/${pollId}`) .then(({ data }) => { dispatch(importFetchedPoll(data)); dispatch(fetchPollSuccess(data)); diff --git a/app/javascript/mastodon/actions/reports.js b/app/javascript/mastodon/actions/reports.js index 756b8cd05e..49b89b0d13 100644 --- a/app/javascript/mastodon/actions/reports.js +++ b/app/javascript/mastodon/actions/reports.js @@ -15,10 +15,10 @@ export const initReport = (account, status) => dispatch => }, })); -export const submitReport = (params, onSuccess, onFail) => (dispatch, getState) => { +export const submitReport = (params, onSuccess, onFail) => (dispatch) => { dispatch(submitReportRequest()); - api(getState).post('/api/v1/reports', params).then(response => { + api().post('/api/v1/reports', params).then(response => { dispatch(submitReportSuccess(response.data)); if (onSuccess) onSuccess(); }).catch(error => { diff --git a/app/javascript/mastodon/actions/search.js b/app/javascript/mastodon/actions/search.js index a34a490e76..bde17ae0db 100644 --- a/app/javascript/mastodon/actions/search.js +++ b/app/javascript/mastodon/actions/search.js @@ -46,7 +46,7 @@ export function submitSearch(type) { dispatch(fetchSearchRequest(type)); - api(getState).get('/api/v2/search', { + api().get('/api/v2/search', { params: { q: value, resolve: signedIn, @@ -99,7 +99,7 @@ export const expandSearch = type => (dispatch, getState) => { dispatch(expandSearchRequest(type)); - api(getState).get('/api/v2/search', { + api().get('/api/v2/search', { params: { q: value, type, @@ -156,7 +156,7 @@ export const openURL = (value, history, onFailure) => (dispatch, getState) => { dispatch(fetchSearchRequest()); - api(getState).get('/api/v2/search', { params: { q: value, resolve: true } }).then(response => { + api().get('/api/v2/search', { params: { q: value, resolve: true } }).then(response => { if (response.data.accounts?.length > 0) { dispatch(importFetchedAccounts(response.data.accounts)); history.push(`/@${response.data.accounts[0].acct}`); diff --git a/app/javascript/mastodon/actions/server.js b/app/javascript/mastodon/actions/server.js index 65f3efc3a7..32ee093afa 100644 --- a/app/javascript/mastodon/actions/server.js +++ b/app/javascript/mastodon/actions/server.js @@ -25,7 +25,7 @@ export const fetchServer = () => (dispatch, getState) => { dispatch(fetchServerRequest()); - api(getState) + api() .get('/api/v2/instance').then(({ data }) => { if (data.contact.account) dispatch(importFetchedAccount(data.contact.account)); dispatch(fetchServerSuccess(data)); @@ -46,10 +46,10 @@ const fetchServerFail = error => ({ error, }); -export const fetchServerTranslationLanguages = () => (dispatch, getState) => { +export const fetchServerTranslationLanguages = () => (dispatch) => { dispatch(fetchServerTranslationLanguagesRequest()); - api(getState) + api() .get('/api/v1/instance/translation_languages').then(({ data }) => { dispatch(fetchServerTranslationLanguagesSuccess(data)); }).catch(err => dispatch(fetchServerTranslationLanguagesFail(err))); @@ -76,7 +76,7 @@ export const fetchExtendedDescription = () => (dispatch, getState) => { dispatch(fetchExtendedDescriptionRequest()); - api(getState) + api() .get('/api/v1/instance/extended_description') .then(({ data }) => dispatch(fetchExtendedDescriptionSuccess(data))) .catch(err => dispatch(fetchExtendedDescriptionFail(err))); @@ -103,7 +103,7 @@ export const fetchDomainBlocks = () => (dispatch, getState) => { dispatch(fetchDomainBlocksRequest()); - api(getState) + api() .get('/api/v1/instance/domain_blocks') .then(({ data }) => dispatch(fetchDomainBlocksSuccess(true, data))) .catch(err => { diff --git a/app/javascript/mastodon/actions/statuses.js b/app/javascript/mastodon/actions/statuses.js index 3aed807358..a60b80dc2c 100644 --- a/app/javascript/mastodon/actions/statuses.js +++ b/app/javascript/mastodon/actions/statuses.js @@ -59,7 +59,7 @@ export function fetchStatus(id, forceFetch = false) { dispatch(fetchStatusRequest(id, skipLoading)); - api(getState).get(`/api/v1/statuses/${id}`).then(response => { + api().get(`/api/v1/statuses/${id}`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(fetchStatusSuccess(skipLoading)); }).catch(error => { @@ -102,7 +102,7 @@ export const editStatus = (id, routerHistory) => (dispatch, getState) => { dispatch(fetchStatusSourceRequest()); - api(getState).get(`/api/v1/statuses/${id}/source`).then(response => { + api().get(`/api/v1/statuses/${id}/source`).then(response => { dispatch(fetchStatusSourceSuccess()); ensureComposeIsVisible(getState, routerHistory); dispatch(setComposeToStatus(status, response.data.text, response.data.spoiler_text)); @@ -134,7 +134,7 @@ export function deleteStatus(id, routerHistory, withRedraft = false) { dispatch(deleteStatusRequest(id)); - api(getState).delete(`/api/v1/statuses/${id}`).then(response => { + api().delete(`/api/v1/statuses/${id}`).then(response => { dispatch(deleteStatusSuccess(id)); dispatch(deleteFromTimelines(id)); dispatch(importFetchedAccount(response.data.account)); @@ -175,10 +175,10 @@ export const updateStatus = status => dispatch => dispatch(importFetchedStatus(status)); export function fetchContext(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchContextRequest(id)); - api(getState).get(`/api/v1/statuses/${id}/context`).then(response => { + api().get(`/api/v1/statuses/${id}/context`).then(response => { dispatch(importFetchedStatuses(response.data.ancestors.concat(response.data.descendants))); dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants)); @@ -219,10 +219,10 @@ export function fetchContextFail(id, error) { } export function muteStatus(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(muteStatusRequest(id)); - api(getState).post(`/api/v1/statuses/${id}/mute`).then(() => { + api().post(`/api/v1/statuses/${id}/mute`).then(() => { dispatch(muteStatusSuccess(id)); }).catch(error => { dispatch(muteStatusFail(id, error)); @@ -253,10 +253,10 @@ export function muteStatusFail(id, error) { } export function unmuteStatus(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unmuteStatusRequest(id)); - api(getState).post(`/api/v1/statuses/${id}/unmute`).then(() => { + api().post(`/api/v1/statuses/${id}/unmute`).then(() => { dispatch(unmuteStatusSuccess(id)); }).catch(error => { dispatch(unmuteStatusFail(id, error)); @@ -316,10 +316,10 @@ export function toggleStatusCollapse(id, isCollapsed) { }; } -export const translateStatus = id => (dispatch, getState) => { +export const translateStatus = id => (dispatch) => { dispatch(translateStatusRequest(id)); - api(getState).post(`/api/v1/statuses/${id}/translate`).then(response => { + api().post(`/api/v1/statuses/${id}/translate`).then(response => { dispatch(translateStatusSuccess(id, response.data)); }).catch(error => { dispatch(translateStatusFail(id, error)); diff --git a/app/javascript/mastodon/actions/suggestions.js b/app/javascript/mastodon/actions/suggestions.js index 8eafe38b21..258ffa901d 100644 --- a/app/javascript/mastodon/actions/suggestions.js +++ b/app/javascript/mastodon/actions/suggestions.js @@ -10,10 +10,10 @@ export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL'; export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS'; export function fetchSuggestions(withRelationships = false) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchSuggestionsRequest()); - api(getState).get('/api/v2/suggestions', { params: { limit: 20 } }).then(response => { + api().get('/api/v2/suggestions', { params: { limit: 20 } }).then(response => { dispatch(importFetchedAccounts(response.data.map(x => x.account))); dispatch(fetchSuggestionsSuccess(response.data)); @@ -48,11 +48,11 @@ export function fetchSuggestionsFail(error) { }; } -export const dismissSuggestion = accountId => (dispatch, getState) => { +export const dismissSuggestion = accountId => (dispatch) => { dispatch({ type: SUGGESTIONS_DISMISS, id: accountId, }); - api(getState).delete(`/api/v1/suggestions/${accountId}`).catch(() => {}); + api().delete(`/api/v1/suggestions/${accountId}`).catch(() => {}); }; diff --git a/app/javascript/mastodon/actions/tags.js b/app/javascript/mastodon/actions/tags.js index dda8c924bb..d18d7e514f 100644 --- a/app/javascript/mastodon/actions/tags.js +++ b/app/javascript/mastodon/actions/tags.js @@ -20,10 +20,10 @@ export const HASHTAG_UNFOLLOW_REQUEST = 'HASHTAG_UNFOLLOW_REQUEST'; export const HASHTAG_UNFOLLOW_SUCCESS = 'HASHTAG_UNFOLLOW_SUCCESS'; export const HASHTAG_UNFOLLOW_FAIL = 'HASHTAG_UNFOLLOW_FAIL'; -export const fetchHashtag = name => (dispatch, getState) => { +export const fetchHashtag = name => (dispatch) => { dispatch(fetchHashtagRequest()); - api(getState).get(`/api/v1/tags/${name}`).then(({ data }) => { + api().get(`/api/v1/tags/${name}`).then(({ data }) => { dispatch(fetchHashtagSuccess(name, data)); }).catch(err => { dispatch(fetchHashtagFail(err)); @@ -45,10 +45,10 @@ export const fetchHashtagFail = error => ({ error, }); -export const fetchFollowedHashtags = () => (dispatch, getState) => { +export const fetchFollowedHashtags = () => (dispatch) => { dispatch(fetchFollowedHashtagsRequest()); - api(getState).get('/api/v1/followed_tags').then(response => { + api().get('/api/v1/followed_tags').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(fetchFollowedHashtagsSuccess(response.data, next ? next.uri : null)); }).catch(err => { @@ -87,7 +87,7 @@ export function expandFollowedHashtags() { dispatch(expandFollowedHashtagsRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(expandFollowedHashtagsSuccess(response.data, next ? next.uri : null)); }).catch(error => { @@ -117,10 +117,10 @@ export function expandFollowedHashtagsFail(error) { }; } -export const followHashtag = name => (dispatch, getState) => { +export const followHashtag = name => (dispatch) => { dispatch(followHashtagRequest(name)); - api(getState).post(`/api/v1/tags/${name}/follow`).then(({ data }) => { + api().post(`/api/v1/tags/${name}/follow`).then(({ data }) => { dispatch(followHashtagSuccess(name, data)); }).catch(err => { dispatch(followHashtagFail(name, err)); @@ -144,10 +144,10 @@ export const followHashtagFail = (name, error) => ({ error, }); -export const unfollowHashtag = name => (dispatch, getState) => { +export const unfollowHashtag = name => (dispatch) => { dispatch(unfollowHashtagRequest(name)); - api(getState).post(`/api/v1/tags/${name}/unfollow`).then(({ data }) => { + api().post(`/api/v1/tags/${name}/unfollow`).then(({ data }) => { dispatch(unfollowHashtagSuccess(name, data)); }).catch(err => { dispatch(unfollowHashtagFail(name, err)); diff --git a/app/javascript/mastodon/actions/timelines.js b/app/javascript/mastodon/actions/timelines.js index 4ce7c3cf84..dc37cdf1f1 100644 --- a/app/javascript/mastodon/actions/timelines.js +++ b/app/javascript/mastodon/actions/timelines.js @@ -114,7 +114,7 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) { dispatch(expandTimelineRequest(timelineId, isLoadingMore)); - api(getState).get(path, { params }).then(response => { + api().get(path, { params }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); diff --git a/app/javascript/mastodon/actions/trends.js b/app/javascript/mastodon/actions/trends.js index d314423884..0b840b41ce 100644 --- a/app/javascript/mastodon/actions/trends.js +++ b/app/javascript/mastodon/actions/trends.js @@ -18,10 +18,10 @@ export const TRENDS_STATUSES_EXPAND_REQUEST = 'TRENDS_STATUSES_EXPAND_REQUEST'; export const TRENDS_STATUSES_EXPAND_SUCCESS = 'TRENDS_STATUSES_EXPAND_SUCCESS'; export const TRENDS_STATUSES_EXPAND_FAIL = 'TRENDS_STATUSES_EXPAND_FAIL'; -export const fetchTrendingHashtags = () => (dispatch, getState) => { +export const fetchTrendingHashtags = () => (dispatch) => { dispatch(fetchTrendingHashtagsRequest()); - api(getState) + api() .get('/api/v1/trends/tags') .then(({ data }) => dispatch(fetchTrendingHashtagsSuccess(data))) .catch(err => dispatch(fetchTrendingHashtagsFail(err))); @@ -45,10 +45,10 @@ export const fetchTrendingHashtagsFail = error => ({ skipAlert: true, }); -export const fetchTrendingLinks = () => (dispatch, getState) => { +export const fetchTrendingLinks = () => (dispatch) => { dispatch(fetchTrendingLinksRequest()); - api(getState) + api() .get('/api/v1/trends/links') .then(({ data }) => dispatch(fetchTrendingLinksSuccess(data))) .catch(err => dispatch(fetchTrendingLinksFail(err))); @@ -79,7 +79,7 @@ export const fetchTrendingStatuses = () => (dispatch, getState) => { dispatch(fetchTrendingStatusesRequest()); - api(getState).get('/api/v1/trends/statuses').then(response => { + api().get('/api/v1/trends/statuses').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(fetchTrendingStatusesSuccess(response.data, next ? next.uri : null)); @@ -115,7 +115,7 @@ export const expandTrendingStatuses = () => (dispatch, getState) => { dispatch(expandTrendingStatusesRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(expandTrendingStatusesSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/mastodon/api.ts b/app/javascript/mastodon/api.ts index de597a3e3b..ccff68c373 100644 --- a/app/javascript/mastodon/api.ts +++ b/app/javascript/mastodon/api.ts @@ -2,8 +2,8 @@ import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios'; import axios from 'axios'; import LinkHeader from 'http-link-header'; +import { getAccessToken } from './initial_state'; import ready from './ready'; -import type { GetState } from './store'; export const getLinks = (response: AxiosResponse) => { const value = response.headers.link as string | undefined; @@ -29,30 +29,22 @@ const setCSRFHeader = () => { void ready(setCSRFHeader); -export const authorizationTokenFromState = (getState?: GetState) => { - return ( - getState && (getState().meta.get('access_token', '') as string | false) - ); -}; +const authorizationTokenFromInitialState = (): RawAxiosRequestHeaders => { + const accessToken = getAccessToken(); -const authorizationHeaderFromState = (getState?: GetState) => { - const accessToken = authorizationTokenFromState(getState); - - if (!accessToken) { - return {}; - } + if (!accessToken) return {}; return { Authorization: `Bearer ${accessToken}`, - } as RawAxiosRequestHeaders; + }; }; // eslint-disable-next-line import/no-default-export -export default function api(getState: GetState) { +export default function api() { return axios.create({ headers: { ...csrfHeader, - ...authorizationHeaderFromState(getState), + ...authorizationTokenFromInitialState(), }, transformResponse: [ diff --git a/app/javascript/mastodon/identity_context.tsx b/app/javascript/mastodon/identity_context.tsx index 564b7895c9..7f28ab77a3 100644 --- a/app/javascript/mastodon/identity_context.tsx +++ b/app/javascript/mastodon/identity_context.tsx @@ -9,7 +9,6 @@ export interface IdentityContextType { signedIn: boolean; accountId: string | undefined; disabledAccountId: string | undefined; - accessToken: string | undefined; permissions: number; } @@ -17,14 +16,12 @@ export const identityContextPropShape = PropTypes.shape({ signedIn: PropTypes.bool.isRequired, accountId: PropTypes.string, disabledAccountId: PropTypes.string, - accessToken: PropTypes.string, }).isRequired; export const createIdentityContext = (state: InitialState) => ({ signedIn: !!state.meta.me, accountId: state.meta.me, disabledAccountId: state.meta.disabled_account_id, - accessToken: state.meta.access_token, permissions: state.role?.permissions ?? 0, }); @@ -33,7 +30,6 @@ export const IdentityContext = createContext({ permissions: 0, accountId: undefined, disabledAccountId: undefined, - accessToken: undefined, }); export const useIdentity = () => useContext(IdentityContext); diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index 5d60565e17..9ec3df0df8 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -117,4 +117,11 @@ export const criticalUpdatesPending = initialState?.critical_updates_pending; export const statusPageUrl = getMeta('status_page_url'); export const sso_redirect = getMeta('sso_redirect'); +/** + * @returns {string | undefined} + */ +export function getAccessToken() { + return getMeta('access_token'); +} + export default initialState; diff --git a/app/javascript/mastodon/reducers/meta.js b/app/javascript/mastodon/reducers/meta.js index 96baf2f115..ddb7884592 100644 --- a/app/javascript/mastodon/reducers/meta.js +++ b/app/javascript/mastodon/reducers/meta.js @@ -6,7 +6,6 @@ import { layoutFromWindow } from 'mastodon/is_mobile'; const initialState = ImmutableMap({ streaming_api_base_url: null, - access_token: null, layout: layoutFromWindow(), permissions: '0', }); @@ -14,7 +13,8 @@ const initialState = ImmutableMap({ export default function meta(state = initialState, action) { switch(action.type) { case STORE_HYDRATE: - return state.merge(action.state.get('meta')).set('permissions', action.state.getIn(['role', 'permissions'])); + // we do not want `access_token` to be stored in the state + return state.merge(action.state.get('meta')).delete('access_token').set('permissions', action.state.getIn(['role', 'permissions'])); case changeLayout.type: return state.set('layout', action.payload.layout); default: diff --git a/app/javascript/mastodon/stream.js b/app/javascript/mastodon/stream.js index ff3af5fd88..40d69136a8 100644 --- a/app/javascript/mastodon/stream.js +++ b/app/javascript/mastodon/stream.js @@ -2,6 +2,8 @@ import WebSocketClient from '@gamestdio/websocket'; +import { getAccessToken } from './initial_state'; + /** * @type {WebSocketClient | undefined} */ @@ -145,9 +147,11 @@ const channelNameWithInlineParams = (channelName, params) => { // @ts-expect-error export const connectStream = (channelName, params, callbacks) => (dispatch, getState) => { const streamingAPIBaseURL = getState().getIn(['meta', 'streaming_api_base_url']); - const accessToken = getState().getIn(['meta', 'access_token']); + const accessToken = getAccessToken(); const { onConnect, onReceive, onDisconnect } = callbacks(dispatch, getState); + if(!accessToken) throw new Error("Trying to connect to the streaming server but no access token is available."); + // If we cannot use a websockets connection, we must fall back // to using individual connections for each channel if (!streamingAPIBaseURL.startsWith('ws')) { diff --git a/app/javascript/mastodon/test_helpers.tsx b/app/javascript/mastodon/test_helpers.tsx index bfea3f6bf4..93b5a8453a 100644 --- a/app/javascript/mastodon/test_helpers.tsx +++ b/app/javascript/mastodon/test_helpers.tsx @@ -14,7 +14,6 @@ function render( const fakeIdentity = { signedIn: signedIn, accountId: '123', - accessToken: 'test-access-token', disabledAccountId: undefined, permissions: 0, }; From 3e9298370dafb0e7c7a1bc34e524266e96fd50b5 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Wed, 22 May 2024 16:45:18 +0200 Subject: [PATCH 223/658] [Glitch] Remove the access token from Redux & context Port 2c5ab8f647841ea8075ece50ccc9e12c21af8720 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/account_notes.ts | 4 +- .../flavours/glitch/actions/accounts.js | 72 +++++++++---------- .../flavours/glitch/actions/announcements.js | 14 ++-- .../flavours/glitch/actions/blocks.js | 6 +- .../flavours/glitch/actions/bookmarks.js | 4 +- .../flavours/glitch/actions/compose.js | 16 ++--- .../flavours/glitch/actions/conversations.js | 10 +-- .../flavours/glitch/actions/custom_emojis.js | 4 +- .../flavours/glitch/actions/directory.js | 6 +- .../flavours/glitch/actions/domain_blocks.js | 10 +-- .../flavours/glitch/actions/favourites.js | 4 +- .../flavours/glitch/actions/featured_tags.js | 2 +- .../flavours/glitch/actions/filters.js | 12 ++-- .../flavours/glitch/actions/history.js | 2 +- .../flavours/glitch/actions/interactions.js | 44 ++++++------ .../flavours/glitch/actions/lists.js | 39 +++++----- .../flavours/glitch/actions/markers.ts | 34 ++++----- .../flavours/glitch/actions/mutes.js | 6 +- .../flavours/glitch/actions/notifications.js | 34 ++++----- .../flavours/glitch/actions/pin_statuses.js | 4 +- .../flavours/glitch/actions/polls.js | 8 +-- .../flavours/glitch/actions/reports.js | 4 +- .../flavours/glitch/actions/search.js | 6 +- .../flavours/glitch/actions/server.js | 10 +-- .../flavours/glitch/actions/statuses.js | 22 +++--- .../flavours/glitch/actions/suggestions.js | 8 +-- .../flavours/glitch/actions/tags.js | 18 ++--- .../flavours/glitch/actions/timelines.js | 2 +- .../flavours/glitch/actions/trends.js | 12 ++-- app/javascript/flavours/glitch/api.ts | 22 ++---- .../flavours/glitch/identity_context.tsx | 4 -- .../flavours/glitch/initial_state.js | 7 ++ .../flavours/glitch/reducers/meta.js | 4 +- app/javascript/flavours/glitch/stream.js | 6 +- .../flavours/glitch/test_helpers.tsx | 2 - 35 files changed, 230 insertions(+), 232 deletions(-) diff --git a/app/javascript/flavours/glitch/actions/account_notes.ts b/app/javascript/flavours/glitch/actions/account_notes.ts index 1fb683e0d3..b3e79a92c6 100644 --- a/app/javascript/flavours/glitch/actions/account_notes.ts +++ b/app/javascript/flavours/glitch/actions/account_notes.ts @@ -5,8 +5,8 @@ import api from '../api'; export const submitAccountNote = createAppAsyncThunk( 'account_note/submit', - async (args: { id: string; value: string }, { getState }) => { - const response = await api(getState).post( + async (args: { id: string; value: string }) => { + const response = await api().post( `/api/v1/accounts/${args.id}/note`, { comment: args.value, diff --git a/app/javascript/flavours/glitch/actions/accounts.js b/app/javascript/flavours/glitch/actions/accounts.js index bb26035e97..7c31c16998 100644 --- a/app/javascript/flavours/glitch/actions/accounts.js +++ b/app/javascript/flavours/glitch/actions/accounts.js @@ -89,11 +89,11 @@ export const ACCOUNT_REVEAL = 'ACCOUNT_REVEAL'; export * from './accounts_typed'; export function fetchAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchRelationships([id])); dispatch(fetchAccountRequest(id)); - api(getState).get(`/api/v1/accounts/${id}`).then(response => { + api().get(`/api/v1/accounts/${id}`).then(response => { dispatch(importFetchedAccount(response.data)); dispatch(fetchAccountSuccess()); }).catch(error => { @@ -102,10 +102,10 @@ export function fetchAccount(id) { }; } -export const lookupAccount = acct => (dispatch, getState) => { +export const lookupAccount = acct => (dispatch) => { dispatch(lookupAccountRequest(acct)); - api(getState).get('/api/v1/accounts/lookup', { params: { acct } }).then(response => { + api().get('/api/v1/accounts/lookup', { params: { acct } }).then(response => { dispatch(fetchRelationships([response.data.id])); dispatch(importFetchedAccount(response.data)); dispatch(lookupAccountSuccess()); @@ -159,7 +159,7 @@ export function followAccount(id, options = { reblogs: true }) { dispatch(followAccountRequest({ id, locked })); - api(getState).post(`/api/v1/accounts/${id}/follow`, options).then(response => { + api().post(`/api/v1/accounts/${id}/follow`, options).then(response => { dispatch(followAccountSuccess({relationship: response.data, alreadyFollowing})); }).catch(error => { dispatch(followAccountFail({ id, error, locked })); @@ -171,7 +171,7 @@ export function unfollowAccount(id) { return (dispatch, getState) => { dispatch(unfollowAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/unfollow`).then(response => { + api().post(`/api/v1/accounts/${id}/unfollow`).then(response => { dispatch(unfollowAccountSuccess({relationship: response.data, statuses: getState().get('statuses')})); }).catch(error => { dispatch(unfollowAccountFail({ id, error })); @@ -183,7 +183,7 @@ export function blockAccount(id) { return (dispatch, getState) => { dispatch(blockAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/block`).then(response => { + api().post(`/api/v1/accounts/${id}/block`).then(response => { // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers dispatch(blockAccountSuccess({ relationship: response.data, statuses: getState().get('statuses') })); }).catch(error => { @@ -193,10 +193,10 @@ export function blockAccount(id) { } export function unblockAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unblockAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/unblock`).then(response => { + api().post(`/api/v1/accounts/${id}/unblock`).then(response => { dispatch(unblockAccountSuccess({ relationship: response.data })); }).catch(error => { dispatch(unblockAccountFail({ id, error })); @@ -236,7 +236,7 @@ export function muteAccount(id, notifications, duration=0) { return (dispatch, getState) => { dispatch(muteAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications, duration }).then(response => { + api().post(`/api/v1/accounts/${id}/mute`, { notifications, duration }).then(response => { // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers dispatch(muteAccountSuccess({ relationship: response.data, statuses: getState().get('statuses') })); }).catch(error => { @@ -246,10 +246,10 @@ export function muteAccount(id, notifications, duration=0) { } export function unmuteAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unmuteAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/unmute`).then(response => { + api().post(`/api/v1/accounts/${id}/unmute`).then(response => { dispatch(unmuteAccountSuccess({ relationship: response.data })); }).catch(error => { dispatch(unmuteAccountFail({ id, error })); @@ -287,10 +287,10 @@ export function unmuteAccountFail(error) { export function fetchFollowers(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchFollowersRequest(id)); - api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => { + api().get(`/api/v1/accounts/${id}/followers`).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -337,7 +337,7 @@ export function expandFollowers(id) { dispatch(expandFollowersRequest(id)); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -374,10 +374,10 @@ export function expandFollowersFail(id, error) { } export function fetchFollowing(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchFollowingRequest(id)); - api(getState).get(`/api/v1/accounts/${id}/following`).then(response => { + api().get(`/api/v1/accounts/${id}/following`).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -424,7 +424,7 @@ export function expandFollowing(id) { dispatch(expandFollowingRequest(id)); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -473,7 +473,7 @@ export function fetchRelationships(accountIds) { dispatch(fetchRelationshipsRequest(newAccountIds)); - api(getState).get(`/api/v1/accounts/relationships?with_suspended=true&${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => { + api().get(`/api/v1/accounts/relationships?with_suspended=true&${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => { dispatch(fetchRelationshipsSuccess({ relationships: response.data })); }).catch(error => { dispatch(fetchRelationshipsFail(error)); @@ -499,10 +499,10 @@ export function fetchRelationshipsFail(error) { } export function fetchFollowRequests() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchFollowRequestsRequest()); - api(getState).get('/api/v1/follow_requests').then(response => { + api().get('/api/v1/follow_requests').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null)); @@ -541,7 +541,7 @@ export function expandFollowRequests() { dispatch(expandFollowRequestsRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null)); @@ -571,10 +571,10 @@ export function expandFollowRequestsFail(error) { } export function authorizeFollowRequest(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(authorizeFollowRequestRequest(id)); - api(getState) + api() .post(`/api/v1/follow_requests/${id}/authorize`) .then(() => dispatch(authorizeFollowRequestSuccess({ id }))) .catch(error => dispatch(authorizeFollowRequestFail(id, error))); @@ -598,10 +598,10 @@ export function authorizeFollowRequestFail(id, error) { export function rejectFollowRequest(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(rejectFollowRequestRequest(id)); - api(getState) + api() .post(`/api/v1/follow_requests/${id}/reject`) .then(() => dispatch(rejectFollowRequestSuccess({ id }))) .catch(error => dispatch(rejectFollowRequestFail(id, error))); @@ -624,10 +624,10 @@ export function rejectFollowRequestFail(id, error) { } export function pinAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(pinAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/pin`).then(response => { + api().post(`/api/v1/accounts/${id}/pin`).then(response => { dispatch(pinAccountSuccess({ relationship: response.data })); }).catch(error => { dispatch(pinAccountFail(error)); @@ -636,10 +636,10 @@ export function pinAccount(id) { } export function unpinAccount(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unpinAccountRequest(id)); - api(getState).post(`/api/v1/accounts/${id}/unpin`).then(response => { + api().post(`/api/v1/accounts/${id}/unpin`).then(response => { dispatch(unpinAccountSuccess({ relationship: response.data })); }).catch(error => { dispatch(unpinAccountFail(error)); @@ -676,10 +676,10 @@ export function unpinAccountFail(error) { } export function fetchPinnedAccounts() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchPinnedAccountsRequest()); - api(getState).get('/api/v1/endorsements', { params: { limit: 0 } }).then(response => { + api().get('/api/v1/endorsements', { params: { limit: 0 } }).then(response => { dispatch(importFetchedAccounts(response.data)); dispatch(fetchPinnedAccountsSuccess(response.data)); }).catch(err => dispatch(fetchPinnedAccountsFail(err))); @@ -707,7 +707,7 @@ export function fetchPinnedAccountsFail(error) { }; } -export const updateAccount = ({ displayName, note, avatar, header, discoverable, indexable }) => (dispatch, getState) => { +export const updateAccount = ({ displayName, note, avatar, header, discoverable, indexable }) => (dispatch) => { const data = new FormData(); data.append('display_name', displayName); @@ -717,13 +717,13 @@ export const updateAccount = ({ displayName, note, avatar, header, discoverable, data.append('discoverable', discoverable); data.append('indexable', indexable); - return api(getState).patch('/api/v1/accounts/update_credentials', data).then(response => { + return api().patch('/api/v1/accounts/update_credentials', data).then(response => { dispatch(importFetchedAccount(response.data)); }); }; export function fetchPinnedAccountsSuggestions(q) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchPinnedAccountsSuggestionsRequest()); const params = { @@ -733,7 +733,7 @@ export function fetchPinnedAccountsSuggestions(q) { following: true, }; - api(getState).get('/api/v1/accounts/search', { params }).then(response => { + api().get('/api/v1/accounts/search', { params }).then(response => { dispatch(importFetchedAccounts(response.data)); dispatch(fetchPinnedAccountsSuggestionsSuccess(q, response.data)); }).catch(err => dispatch(fetchPinnedAccountsSuggestionsFail(err))); diff --git a/app/javascript/flavours/glitch/actions/announcements.js b/app/javascript/flavours/glitch/actions/announcements.js index 339c5f3adc..7657b05dc4 100644 --- a/app/javascript/flavours/glitch/actions/announcements.js +++ b/app/javascript/flavours/glitch/actions/announcements.js @@ -26,10 +26,10 @@ export const ANNOUNCEMENTS_TOGGLE_SHOW = 'ANNOUNCEMENTS_TOGGLE_SHOW'; const noOp = () => {}; -export const fetchAnnouncements = (done = noOp) => (dispatch, getState) => { +export const fetchAnnouncements = (done = noOp) => (dispatch) => { dispatch(fetchAnnouncementsRequest()); - api(getState).get('/api/v1/announcements').then(response => { + api().get('/api/v1/announcements').then(response => { dispatch(fetchAnnouncementsSuccess(response.data.map(x => normalizeAnnouncement(x)))); }).catch(error => { dispatch(fetchAnnouncementsFail(error)); @@ -61,10 +61,10 @@ export const updateAnnouncements = announcement => ({ announcement: normalizeAnnouncement(announcement), }); -export const dismissAnnouncement = announcementId => (dispatch, getState) => { +export const dismissAnnouncement = announcementId => (dispatch) => { dispatch(dismissAnnouncementRequest(announcementId)); - api(getState).post(`/api/v1/announcements/${announcementId}/dismiss`).then(() => { + api().post(`/api/v1/announcements/${announcementId}/dismiss`).then(() => { dispatch(dismissAnnouncementSuccess(announcementId)); }).catch(error => { dispatch(dismissAnnouncementFail(announcementId, error)); @@ -103,7 +103,7 @@ export const addReaction = (announcementId, name) => (dispatch, getState) => { dispatch(addReactionRequest(announcementId, name, alreadyAdded)); } - api(getState).put(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => { + api().put(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => { dispatch(addReactionSuccess(announcementId, name, alreadyAdded)); }).catch(err => { if (!alreadyAdded) { @@ -134,10 +134,10 @@ export const addReactionFail = (announcementId, name, error) => ({ skipLoading: true, }); -export const removeReaction = (announcementId, name) => (dispatch, getState) => { +export const removeReaction = (announcementId, name) => (dispatch) => { dispatch(removeReactionRequest(announcementId, name)); - api(getState).delete(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => { + api().delete(`/api/v1/announcements/${announcementId}/reactions/${encodeURIComponent(name)}`).then(() => { dispatch(removeReactionSuccess(announcementId, name)); }).catch(err => { dispatch(removeReactionFail(announcementId, name, err)); diff --git a/app/javascript/flavours/glitch/actions/blocks.js b/app/javascript/flavours/glitch/actions/blocks.js index 54296d0905..5c66e27bec 100644 --- a/app/javascript/flavours/glitch/actions/blocks.js +++ b/app/javascript/flavours/glitch/actions/blocks.js @@ -13,10 +13,10 @@ export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS'; export const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL'; export function fetchBlocks() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchBlocksRequest()); - api(getState).get('/api/v1/blocks').then(response => { + api().get('/api/v1/blocks').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null)); @@ -56,7 +56,7 @@ export function expandBlocks() { dispatch(expandBlocksRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(expandBlocksSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/flavours/glitch/actions/bookmarks.js b/app/javascript/flavours/glitch/actions/bookmarks.js index 0b16f61e63..89716b224c 100644 --- a/app/javascript/flavours/glitch/actions/bookmarks.js +++ b/app/javascript/flavours/glitch/actions/bookmarks.js @@ -18,7 +18,7 @@ export function fetchBookmarkedStatuses() { dispatch(fetchBookmarkedStatusesRequest()); - api(getState).get('/api/v1/bookmarks').then(response => { + api().get('/api/v1/bookmarks').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(fetchBookmarkedStatusesSuccess(response.data, next ? next.uri : null)); @@ -59,7 +59,7 @@ export function expandBookmarkedStatuses() { dispatch(expandBookmarkedStatusesRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(expandBookmarkedStatusesSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index 1dca94ae68..61245acdba 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -211,7 +211,7 @@ export function submitCompose(routerHistory, overridePrivacy = null) { }); } - api(getState).request({ + api().request({ url: statusId === null ? '/api/v1/statuses' : `/api/v1/statuses/${statusId}`, method: statusId === null ? 'post' : 'put', data: { @@ -338,7 +338,7 @@ export function uploadCompose(files) { // Account for disparity in size of original image and resized data total += file.size - f.size; - return api(getState).post('/api/v2/media', data, { + return api().post('/api/v2/media', data, { onUploadProgress: function({ loaded }){ progress[i] = loaded; dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total)); @@ -355,7 +355,7 @@ export function uploadCompose(files) { let tryCount = 1; const poll = () => { - api(getState).get(`/api/v1/media/${data.id}`).then(response => { + api().get(`/api/v1/media/${data.id}`).then(response => { if (response.status === 200) { dispatch(uploadComposeSuccess(response.data, f)); } else if (response.status === 206) { @@ -378,7 +378,7 @@ export const uploadComposeProcessing = () => ({ type: COMPOSE_UPLOAD_PROCESSING, }); -export const uploadThumbnail = (id, file) => (dispatch, getState) => { +export const uploadThumbnail = (id, file) => (dispatch) => { dispatch(uploadThumbnailRequest()); const total = file.size; @@ -386,7 +386,7 @@ export const uploadThumbnail = (id, file) => (dispatch, getState) => { data.append('thumbnail', file); - api(getState).put(`/api/v1/media/${id}`, data, { + api().put(`/api/v1/media/${id}`, data, { onUploadProgress: ({ loaded }) => { dispatch(uploadThumbnailProgress(loaded, total)); }, @@ -469,7 +469,7 @@ export function changeUploadCompose(id, params) { dispatch(changeUploadComposeSuccess(data, true)); } else { - api(getState).put(`/api/v1/media/${id}`, params).then(response => { + api().put(`/api/v1/media/${id}`, params).then(response => { dispatch(changeUploadComposeSuccess(response.data, false)); }).catch(error => { dispatch(changeUploadComposeFail(id, error)); @@ -557,7 +557,7 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => fetchComposeSuggestionsAccountsController = new AbortController(); - api(getState).get('/api/v1/accounts/search', { + api().get('/api/v1/accounts/search', { signal: fetchComposeSuggestionsAccountsController.signal, params: { @@ -591,7 +591,7 @@ const fetchComposeSuggestionsTags = throttle((dispatch, getState, token) => { fetchComposeSuggestionsTagsController = new AbortController(); - api(getState).get('/api/v2/search', { + api().get('/api/v2/search', { signal: fetchComposeSuggestionsTagsController.signal, params: { diff --git a/app/javascript/flavours/glitch/actions/conversations.js b/app/javascript/flavours/glitch/actions/conversations.js index 8c4c4529fb..03174c485d 100644 --- a/app/javascript/flavours/glitch/actions/conversations.js +++ b/app/javascript/flavours/glitch/actions/conversations.js @@ -28,13 +28,13 @@ export const unmountConversations = () => ({ type: CONVERSATIONS_UNMOUNT, }); -export const markConversationRead = conversationId => (dispatch, getState) => { +export const markConversationRead = conversationId => (dispatch) => { dispatch({ type: CONVERSATIONS_READ, id: conversationId, }); - api(getState).post(`/api/v1/conversations/${conversationId}/read`); + api().post(`/api/v1/conversations/${conversationId}/read`); }; export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => { @@ -48,7 +48,7 @@ export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => { const isLoadingRecent = !!params.since_id; - api(getState).get('/api/v1/conversations', { params }) + api().get('/api/v1/conversations', { params }) .then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); @@ -88,10 +88,10 @@ export const updateConversations = conversation => dispatch => { }); }; -export const deleteConversation = conversationId => (dispatch, getState) => { +export const deleteConversation = conversationId => (dispatch) => { dispatch(deleteConversationRequest(conversationId)); - api(getState).delete(`/api/v1/conversations/${conversationId}`) + api().delete(`/api/v1/conversations/${conversationId}`) .then(() => dispatch(deleteConversationSuccess(conversationId))) .catch(error => dispatch(deleteConversationFail(conversationId, error))); }; diff --git a/app/javascript/flavours/glitch/actions/custom_emojis.js b/app/javascript/flavours/glitch/actions/custom_emojis.js index 9ec8156b17..fb65f072dc 100644 --- a/app/javascript/flavours/glitch/actions/custom_emojis.js +++ b/app/javascript/flavours/glitch/actions/custom_emojis.js @@ -5,10 +5,10 @@ export const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS'; export const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL'; export function fetchCustomEmojis() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchCustomEmojisRequest()); - api(getState).get('/api/v1/custom_emojis').then(response => { + api().get('/api/v1/custom_emojis').then(response => { dispatch(fetchCustomEmojisSuccess(response.data)); }).catch(error => { dispatch(fetchCustomEmojisFail(error)); diff --git a/app/javascript/flavours/glitch/actions/directory.js b/app/javascript/flavours/glitch/actions/directory.js index cda63f2b5a..7a0748029d 100644 --- a/app/javascript/flavours/glitch/actions/directory.js +++ b/app/javascript/flavours/glitch/actions/directory.js @@ -11,10 +11,10 @@ export const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST'; export const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS'; export const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL'; -export const fetchDirectory = params => (dispatch, getState) => { +export const fetchDirectory = params => (dispatch) => { dispatch(fetchDirectoryRequest()); - api(getState).get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => { + api().get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(fetchDirectorySuccess(data)); dispatch(fetchRelationships(data.map(x => x.id))); @@ -40,7 +40,7 @@ export const expandDirectory = params => (dispatch, getState) => { const loadedItems = getState().getIn(['user_lists', 'directory', 'items']).size; - api(getState).get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => { + api().get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(expandDirectorySuccess(data)); dispatch(fetchRelationships(data.map(x => x.id))); diff --git a/app/javascript/flavours/glitch/actions/domain_blocks.js b/app/javascript/flavours/glitch/actions/domain_blocks.js index 55c0a6ce9d..727f800af3 100644 --- a/app/javascript/flavours/glitch/actions/domain_blocks.js +++ b/app/javascript/flavours/glitch/actions/domain_blocks.js @@ -24,7 +24,7 @@ export function blockDomain(domain) { return (dispatch, getState) => { dispatch(blockDomainRequest(domain)); - api(getState).post('/api/v1/domain_blocks', { domain }).then(() => { + api().post('/api/v1/domain_blocks', { domain }).then(() => { const at_domain = '@' + domain; const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id')); @@ -54,7 +54,7 @@ export function unblockDomain(domain) { return (dispatch, getState) => { dispatch(unblockDomainRequest(domain)); - api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(() => { + api().delete('/api/v1/domain_blocks', { params: { domain } }).then(() => { const at_domain = '@' + domain; const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id')); dispatch(unblockDomainSuccess({ domain, accounts })); @@ -80,10 +80,10 @@ export function unblockDomainFail(domain, error) { } export function fetchDomainBlocks() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchDomainBlocksRequest()); - api(getState).get('/api/v1/domain_blocks').then(response => { + api().get('/api/v1/domain_blocks').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null)); }).catch(err => { @@ -123,7 +123,7 @@ export function expandDomainBlocks() { dispatch(expandDomainBlocksRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null)); }).catch(err => { diff --git a/app/javascript/flavours/glitch/actions/favourites.js b/app/javascript/flavours/glitch/actions/favourites.js index 2d4d4e6206..ff475c82be 100644 --- a/app/javascript/flavours/glitch/actions/favourites.js +++ b/app/javascript/flavours/glitch/actions/favourites.js @@ -18,7 +18,7 @@ export function fetchFavouritedStatuses() { dispatch(fetchFavouritedStatusesRequest()); - api(getState).get('/api/v1/favourites').then(response => { + api().get('/api/v1/favourites').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null)); @@ -62,7 +62,7 @@ export function expandFavouritedStatuses() { dispatch(expandFavouritedStatusesRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/flavours/glitch/actions/featured_tags.js b/app/javascript/flavours/glitch/actions/featured_tags.js index 18bb615394..6ee4dee2bc 100644 --- a/app/javascript/flavours/glitch/actions/featured_tags.js +++ b/app/javascript/flavours/glitch/actions/featured_tags.js @@ -11,7 +11,7 @@ export const fetchFeaturedTags = (id) => (dispatch, getState) => { dispatch(fetchFeaturedTagsRequest(id)); - api(getState).get(`/api/v1/accounts/${id}/featured_tags`) + api().get(`/api/v1/accounts/${id}/featured_tags`) .then(({ data }) => dispatch(fetchFeaturedTagsSuccess(id, data))) .catch(err => dispatch(fetchFeaturedTagsFail(id, err))); }; diff --git a/app/javascript/flavours/glitch/actions/filters.js b/app/javascript/flavours/glitch/actions/filters.js index a11956ac56..588e390f0a 100644 --- a/app/javascript/flavours/glitch/actions/filters.js +++ b/app/javascript/flavours/glitch/actions/filters.js @@ -23,13 +23,13 @@ export const initAddFilter = (status, { contextType }) => dispatch => }, })); -export const fetchFilters = () => (dispatch, getState) => { +export const fetchFilters = () => (dispatch) => { dispatch({ type: FILTERS_FETCH_REQUEST, skipLoading: true, }); - api(getState) + api() .get('/api/v2/filters') .then(({ data }) => dispatch({ type: FILTERS_FETCH_SUCCESS, @@ -44,10 +44,10 @@ export const fetchFilters = () => (dispatch, getState) => { })); }; -export const createFilterStatus = (params, onSuccess, onFail) => (dispatch, getState) => { +export const createFilterStatus = (params, onSuccess, onFail) => (dispatch) => { dispatch(createFilterStatusRequest()); - api(getState).post(`/api/v2/filters/${params.filter_id}/statuses`, params).then(response => { + api().post(`/api/v2/filters/${params.filter_id}/statuses`, params).then(response => { dispatch(createFilterStatusSuccess(response.data)); if (onSuccess) onSuccess(); }).catch(error => { @@ -70,10 +70,10 @@ export const createFilterStatusFail = error => ({ error, }); -export const createFilter = (params, onSuccess, onFail) => (dispatch, getState) => { +export const createFilter = (params, onSuccess, onFail) => (dispatch) => { dispatch(createFilterRequest()); - api(getState).post('/api/v2/filters', params).then(response => { + api().post('/api/v2/filters', params).then(response => { dispatch(createFilterSuccess(response.data)); if (onSuccess) onSuccess(response.data); }).catch(error => { diff --git a/app/javascript/flavours/glitch/actions/history.js b/app/javascript/flavours/glitch/actions/history.js index 52401b7dce..07732ea187 100644 --- a/app/javascript/flavours/glitch/actions/history.js +++ b/app/javascript/flavours/glitch/actions/history.js @@ -15,7 +15,7 @@ export const fetchHistory = statusId => (dispatch, getState) => { dispatch(fetchHistoryRequest(statusId)); - api(getState).get(`/api/v1/statuses/${statusId}/history`).then(({ data }) => { + api().get(`/api/v1/statuses/${statusId}/history`).then(({ data }) => { dispatch(importFetchedAccounts(data.map(x => x.account))); dispatch(fetchHistorySuccess(statusId, data)); }).catch(error => dispatch(fetchHistoryFail(error))); diff --git a/app/javascript/flavours/glitch/actions/interactions.js b/app/javascript/flavours/glitch/actions/interactions.js index 7d0144438a..fe7c911b61 100644 --- a/app/javascript/flavours/glitch/actions/interactions.js +++ b/app/javascript/flavours/glitch/actions/interactions.js @@ -52,10 +52,10 @@ export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS'; export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL'; export function reblog(status, visibility) { - return function (dispatch, getState) { + return function (dispatch) { dispatch(reblogRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) { + api().post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) { // The reblog API method returns a new status wrapped around the original. In this case we are only // interested in how the original is modified, hence passing it skipping the wrapper dispatch(importFetchedStatus(response.data.reblog)); @@ -67,10 +67,10 @@ export function reblog(status, visibility) { } export function unreblog(status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unreblogRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unreblogSuccess(status)); }).catch(error => { @@ -130,10 +130,10 @@ export function unreblogFail(status, error) { } export function favourite(status) { - return function (dispatch, getState) { + return function (dispatch) { dispatch(favouriteRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) { + api().post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) { dispatch(importFetchedStatus(response.data)); dispatch(favouriteSuccess(status)); }).catch(function (error) { @@ -143,10 +143,10 @@ export function favourite(status) { } export function unfavourite(status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unfavouriteRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unfavouriteSuccess(status)); }).catch(error => { @@ -206,10 +206,10 @@ export function unfavouriteFail(status, error) { } export function bookmark(status) { - return function (dispatch, getState) { + return function (dispatch) { dispatch(bookmarkRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function (response) { + api().post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function (response) { dispatch(importFetchedStatus(response.data)); dispatch(bookmarkSuccess(status, response.data)); }).catch(function (error) { @@ -219,10 +219,10 @@ export function bookmark(status) { } export function unbookmark(status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unbookmarkRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unbookmarkSuccess(status, response.data)); }).catch(error => { @@ -278,10 +278,10 @@ export function unbookmarkFail(status, error) { } export function fetchReblogs(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchReblogsRequest(id)); - api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => { + api().get(`/api/v1/statuses/${id}/reblogged_by`).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchReblogsSuccess(id, response.data, next ? next.uri : null)); @@ -325,7 +325,7 @@ export function expandReblogs(id) { dispatch(expandReblogsRequest(id)); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -360,10 +360,10 @@ export function expandReblogsFail(id, error) { } export function fetchFavourites(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchFavouritesRequest(id)); - api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => { + api().get(`/api/v1/statuses/${id}/favourited_by`).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchFavouritesSuccess(id, response.data, next ? next.uri : null)); @@ -407,7 +407,7 @@ export function expandFavourites(id) { dispatch(expandFavouritesRequest(id)); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); @@ -442,10 +442,10 @@ export function expandFavouritesFail(id, error) { } export function pin(status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(pinRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(pinSuccess(status)); }).catch(error => { @@ -480,10 +480,10 @@ export function pinFail(status, error) { } export function unpin (status) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unpinRequest(status)); - api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => { + api().post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(unpinSuccess(status)); }).catch(error => { diff --git a/app/javascript/flavours/glitch/actions/lists.js b/app/javascript/flavours/glitch/actions/lists.js index b0789cd426..9956059387 100644 --- a/app/javascript/flavours/glitch/actions/lists.js +++ b/app/javascript/flavours/glitch/actions/lists.js @@ -57,7 +57,7 @@ export const fetchList = id => (dispatch, getState) => { dispatch(fetchListRequest(id)); - api(getState).get(`/api/v1/lists/${id}`) + api().get(`/api/v1/lists/${id}`) .then(({ data }) => dispatch(fetchListSuccess(data))) .catch(err => dispatch(fetchListFail(id, err))); }; @@ -78,10 +78,10 @@ export const fetchListFail = (id, error) => ({ error, }); -export const fetchLists = () => (dispatch, getState) => { +export const fetchLists = () => (dispatch) => { dispatch(fetchListsRequest()); - api(getState).get('/api/v1/lists') + api().get('/api/v1/lists') .then(({ data }) => dispatch(fetchListsSuccess(data))) .catch(err => dispatch(fetchListsFail(err))); }; @@ -125,10 +125,10 @@ export const changeListEditorTitle = value => ({ value, }); -export const createList = (title, shouldReset) => (dispatch, getState) => { +export const createList = (title, shouldReset) => (dispatch) => { dispatch(createListRequest()); - api(getState).post('/api/v1/lists', { title }).then(({ data }) => { + api().post('/api/v1/lists', { title }).then(({ data }) => { dispatch(createListSuccess(data)); if (shouldReset) { @@ -151,10 +151,10 @@ export const createListFail = error => ({ error, }); -export const updateList = (id, title, shouldReset, isExclusive, replies_policy) => (dispatch, getState) => { +export const updateList = (id, title, shouldReset, isExclusive, replies_policy) => (dispatch) => { dispatch(updateListRequest(id)); - api(getState).put(`/api/v1/lists/${id}`, { title, replies_policy, exclusive: typeof isExclusive === 'undefined' ? undefined : !!isExclusive }).then(({ data }) => { + api().put(`/api/v1/lists/${id}`, { title, replies_policy, exclusive: typeof isExclusive === 'undefined' ? undefined : !!isExclusive }).then(({ data }) => { dispatch(updateListSuccess(data)); if (shouldReset) { @@ -183,10 +183,10 @@ export const resetListEditor = () => ({ type: LIST_EDITOR_RESET, }); -export const deleteList = id => (dispatch, getState) => { +export const deleteList = id => (dispatch) => { dispatch(deleteListRequest(id)); - api(getState).delete(`/api/v1/lists/${id}`) + api().delete(`/api/v1/lists/${id}`) .then(() => dispatch(deleteListSuccess(id))) .catch(err => dispatch(deleteListFail(id, err))); }; @@ -207,10 +207,10 @@ export const deleteListFail = (id, error) => ({ error, }); -export const fetchListAccounts = listId => (dispatch, getState) => { +export const fetchListAccounts = listId => (dispatch) => { dispatch(fetchListAccountsRequest(listId)); - api(getState).get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => { + api().get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(fetchListAccountsSuccess(listId, data)); }).catch(err => dispatch(fetchListAccountsFail(listId, err))); @@ -234,7 +234,7 @@ export const fetchListAccountsFail = (id, error) => ({ error, }); -export const fetchListSuggestions = q => (dispatch, getState) => { +export const fetchListSuggestions = q => (dispatch) => { const params = { q, resolve: false, @@ -242,7 +242,7 @@ export const fetchListSuggestions = q => (dispatch, getState) => { following: true, }; - api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => { + api().get('/api/v1/accounts/search', { params }).then(({ data }) => { dispatch(importFetchedAccounts(data)); dispatch(fetchListSuggestionsReady(q, data)); }).catch(error => dispatch(showAlertForError(error))); @@ -267,10 +267,10 @@ export const addToListEditor = accountId => (dispatch, getState) => { dispatch(addToList(getState().getIn(['listEditor', 'listId']), accountId)); }; -export const addToList = (listId, accountId) => (dispatch, getState) => { +export const addToList = (listId, accountId) => (dispatch) => { dispatch(addToListRequest(listId, accountId)); - api(getState).post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] }) + api().post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] }) .then(() => dispatch(addToListSuccess(listId, accountId))) .catch(err => dispatch(addToListFail(listId, accountId, err))); }; @@ -298,10 +298,10 @@ export const removeFromListEditor = accountId => (dispatch, getState) => { dispatch(removeFromList(getState().getIn(['listEditor', 'listId']), accountId)); }; -export const removeFromList = (listId, accountId) => (dispatch, getState) => { +export const removeFromList = (listId, accountId) => (dispatch) => { dispatch(removeFromListRequest(listId, accountId)); - api(getState).delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } }) + api().delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } }) .then(() => dispatch(removeFromListSuccess(listId, accountId))) .catch(err => dispatch(removeFromListFail(listId, accountId, err))); }; @@ -338,10 +338,10 @@ export const setupListAdder = accountId => (dispatch, getState) => { dispatch(fetchAccountLists(accountId)); }; -export const fetchAccountLists = accountId => (dispatch, getState) => { +export const fetchAccountLists = accountId => (dispatch) => { dispatch(fetchAccountListsRequest(accountId)); - api(getState).get(`/api/v1/accounts/${accountId}/lists`) + api().get(`/api/v1/accounts/${accountId}/lists`) .then(({ data }) => dispatch(fetchAccountListsSuccess(accountId, data))) .catch(err => dispatch(fetchAccountListsFail(accountId, err))); }; @@ -370,4 +370,3 @@ export const addToListAdder = listId => (dispatch, getState) => { export const removeFromListAdder = listId => (dispatch, getState) => { dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId']))); }; - diff --git a/app/javascript/flavours/glitch/actions/markers.ts b/app/javascript/flavours/glitch/actions/markers.ts index 3f810cf99a..a85af1c4be 100644 --- a/app/javascript/flavours/glitch/actions/markers.ts +++ b/app/javascript/flavours/glitch/actions/markers.ts @@ -1,19 +1,24 @@ import { debounce } from 'lodash'; import type { MarkerJSON } from 'flavours/glitch/api_types/markers'; +import { getAccessToken } from 'flavours/glitch/initial_state'; import type { AppDispatch, RootState } from 'flavours/glitch/store'; import { createAppAsyncThunk } from 'flavours/glitch/store/typed_functions'; -import api, { authorizationTokenFromState } from '../api'; +import api from '../api'; import { compareId } from '../compare_id'; export const synchronouslySubmitMarkers = createAppAsyncThunk( 'markers/submit', async (_args, { getState }) => { - const accessToken = authorizationTokenFromState(getState); + const accessToken = getAccessToken(); const params = buildPostMarkersParams(getState()); - if (Object.keys(params).length === 0 || !accessToken) { + if ( + Object.keys(params).length === 0 || + !accessToken || + accessToken === '' + ) { return; } @@ -97,14 +102,14 @@ export const submitMarkersAction = createAppAsyncThunk<{ home: string | undefined; notifications: string | undefined; }>('markers/submitAction', async (_args, { getState }) => { - const accessToken = authorizationTokenFromState(getState); + const accessToken = getAccessToken(); const params = buildPostMarkersParams(getState()); - if (Object.keys(params).length === 0 || accessToken === '') { + if (Object.keys(params).length === 0 || !accessToken || accessToken === '') { return { home: undefined, notifications: undefined }; } - await api(getState).post('/api/v1/markers', params); + await api().post('/api/v1/markers', params); return { home: params.home?.last_read_id, @@ -134,14 +139,11 @@ export const submitMarkers = createAppAsyncThunk( }, ); -export const fetchMarkers = createAppAsyncThunk( - 'markers/fetch', - async (_args, { getState }) => { - const response = await api(getState).get>( - `/api/v1/markers`, - { params: { timeline: ['notifications'] } }, - ); +export const fetchMarkers = createAppAsyncThunk('markers/fetch', async () => { + const response = await api().get>( + `/api/v1/markers`, + { params: { timeline: ['notifications'] } }, + ); - return { markers: response.data }; - }, -); + return { markers: response.data }; +}); diff --git a/app/javascript/flavours/glitch/actions/mutes.js b/app/javascript/flavours/glitch/actions/mutes.js index 99c113f414..3676748cf3 100644 --- a/app/javascript/flavours/glitch/actions/mutes.js +++ b/app/javascript/flavours/glitch/actions/mutes.js @@ -13,10 +13,10 @@ export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS'; export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL'; export function fetchMutes() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchMutesRequest()); - api(getState).get('/api/v1/mutes').then(response => { + api().get('/api/v1/mutes').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(fetchMutesSuccess(response.data, next ? next.uri : null)); @@ -56,7 +56,7 @@ export function expandMutes() { dispatch(expandMutesRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data)); dispatch(expandMutesSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index 5b274ff94c..a2be31ffeb 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -228,7 +228,7 @@ export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) { dispatch(expandNotificationsRequest(isLoadingMore)); - api(getState).get('/api/v1/notifications', { params, signal: expandNotificationsController.signal }).then(response => { + api().get('/api/v1/notifications', { params, signal: expandNotificationsController.signal }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(item => item.account))); @@ -274,12 +274,12 @@ export function expandNotificationsFail(error, isLoadingMore) { } export function clearNotifications() { - return (dispatch, getState) => { + return (dispatch) => { dispatch({ type: NOTIFICATIONS_CLEAR, }); - api(getState).post('/api/v1/notifications/clear'); + api().post('/api/v1/notifications/clear'); }; } @@ -305,7 +305,7 @@ export function deleteMarkedNotifications() { return; } - api(getState).delete(`/api/v1/notifications/destroy_multiple?ids[]=${ids.join('&ids[]=')}`).then(() => { + api().delete(`/api/v1/notifications/destroy_multiple?ids[]=${ids.join('&ids[]=')}`).then(() => { dispatch(deleteMarkedNotificationsSuccess()); }).catch(error => { console.error(error); @@ -434,10 +434,10 @@ export function setBrowserPermission (value) { }; } -export const fetchNotificationPolicy = () => (dispatch, getState) => { +export const fetchNotificationPolicy = () => (dispatch) => { dispatch(fetchNotificationPolicyRequest()); - api(getState).get('/api/v1/notifications/policy').then(({ data }) => { + api().get('/api/v1/notifications/policy').then(({ data }) => { dispatch(fetchNotificationPolicySuccess(data)); }).catch(err => { dispatch(fetchNotificationPolicyFail(err)); @@ -458,10 +458,10 @@ export const fetchNotificationPolicyFail = error => ({ error, }); -export const updateNotificationsPolicy = params => (dispatch, getState) => { +export const updateNotificationsPolicy = params => (dispatch) => { dispatch(fetchNotificationPolicyRequest()); - api(getState).put('/api/v1/notifications/policy', params).then(({ data }) => { + api().put('/api/v1/notifications/policy', params).then(({ data }) => { dispatch(fetchNotificationPolicySuccess(data)); }).catch(err => { dispatch(fetchNotificationPolicyFail(err)); @@ -481,7 +481,7 @@ export const fetchNotificationRequests = () => (dispatch, getState) => { dispatch(fetchNotificationRequestsRequest()); - api(getState).get('/api/v1/notifications/requests', { params }).then(response => { + api().get('/api/v1/notifications/requests', { params }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(x => x.account))); dispatch(fetchNotificationRequestsSuccess(response.data, next ? next.uri : null)); @@ -514,7 +514,7 @@ export const expandNotificationRequests = () => (dispatch, getState) => { dispatch(expandNotificationRequestsRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(x => x.account))); dispatch(expandNotificationRequestsSuccess(response.data, next?.uri)); @@ -547,7 +547,7 @@ export const fetchNotificationRequest = id => (dispatch, getState) => { dispatch(fetchNotificationRequestRequest(id)); - api(getState).get(`/api/v1/notifications/requests/${id}`).then(({ data }) => { + api().get(`/api/v1/notifications/requests/${id}`).then(({ data }) => { dispatch(fetchNotificationRequestSuccess(data)); }).catch(err => { dispatch(fetchNotificationRequestFail(id, err)); @@ -570,10 +570,10 @@ export const fetchNotificationRequestFail = (id, error) => ({ error, }); -export const acceptNotificationRequest = id => (dispatch, getState) => { +export const acceptNotificationRequest = id => (dispatch) => { dispatch(acceptNotificationRequestRequest(id)); - api(getState).post(`/api/v1/notifications/requests/${id}/accept`).then(() => { + api().post(`/api/v1/notifications/requests/${id}/accept`).then(() => { dispatch(acceptNotificationRequestSuccess(id)); }).catch(err => { dispatch(acceptNotificationRequestFail(id, err)); @@ -596,10 +596,10 @@ export const acceptNotificationRequestFail = (id, error) => ({ error, }); -export const dismissNotificationRequest = id => (dispatch, getState) => { +export const dismissNotificationRequest = id => (dispatch) => { dispatch(dismissNotificationRequestRequest(id)); - api(getState).post(`/api/v1/notifications/requests/${id}/dismiss`).then(() =>{ + api().post(`/api/v1/notifications/requests/${id}/dismiss`).then(() =>{ dispatch(dismissNotificationRequestSuccess(id)); }).catch(err => { dispatch(dismissNotificationRequestFail(id, err)); @@ -638,7 +638,7 @@ export const fetchNotificationsForRequest = accountId => (dispatch, getState) => dispatch(fetchNotificationsForRequestRequest()); - api(getState).get('/api/v1/notifications', { params }).then(response => { + api().get('/api/v1/notifications', { params }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(item => item.account))); dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status))); @@ -674,7 +674,7 @@ export const expandNotificationsForRequest = () => (dispatch, getState) => { dispatch(expandNotificationsForRequestRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedAccounts(response.data.map(item => item.account))); dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status))); diff --git a/app/javascript/flavours/glitch/actions/pin_statuses.js b/app/javascript/flavours/glitch/actions/pin_statuses.js index baa10d1562..d583eab573 100644 --- a/app/javascript/flavours/glitch/actions/pin_statuses.js +++ b/app/javascript/flavours/glitch/actions/pin_statuses.js @@ -8,10 +8,10 @@ export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS'; export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL'; export function fetchPinnedStatuses() { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchPinnedStatusesRequest()); - api(getState).get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => { + api().get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => { dispatch(importFetchedStatuses(response.data)); dispatch(fetchPinnedStatusesSuccess(response.data, null)); }).catch(error => { diff --git a/app/javascript/flavours/glitch/actions/polls.js b/app/javascript/flavours/glitch/actions/polls.js index a37410dc90..aa49341444 100644 --- a/app/javascript/flavours/glitch/actions/polls.js +++ b/app/javascript/flavours/glitch/actions/polls.js @@ -10,10 +10,10 @@ export const POLL_FETCH_REQUEST = 'POLL_FETCH_REQUEST'; export const POLL_FETCH_SUCCESS = 'POLL_FETCH_SUCCESS'; export const POLL_FETCH_FAIL = 'POLL_FETCH_FAIL'; -export const vote = (pollId, choices) => (dispatch, getState) => { +export const vote = (pollId, choices) => (dispatch) => { dispatch(voteRequest()); - api(getState).post(`/api/v1/polls/${pollId}/votes`, { choices }) + api().post(`/api/v1/polls/${pollId}/votes`, { choices }) .then(({ data }) => { dispatch(importFetchedPoll(data)); dispatch(voteSuccess(data)); @@ -21,10 +21,10 @@ export const vote = (pollId, choices) => (dispatch, getState) => { .catch(err => dispatch(voteFail(err))); }; -export const fetchPoll = pollId => (dispatch, getState) => { +export const fetchPoll = pollId => (dispatch) => { dispatch(fetchPollRequest()); - api(getState).get(`/api/v1/polls/${pollId}`) + api().get(`/api/v1/polls/${pollId}`) .then(({ data }) => { dispatch(importFetchedPoll(data)); dispatch(fetchPollSuccess(data)); diff --git a/app/javascript/flavours/glitch/actions/reports.js b/app/javascript/flavours/glitch/actions/reports.js index 756b8cd05e..49b89b0d13 100644 --- a/app/javascript/flavours/glitch/actions/reports.js +++ b/app/javascript/flavours/glitch/actions/reports.js @@ -15,10 +15,10 @@ export const initReport = (account, status) => dispatch => }, })); -export const submitReport = (params, onSuccess, onFail) => (dispatch, getState) => { +export const submitReport = (params, onSuccess, onFail) => (dispatch) => { dispatch(submitReportRequest()); - api(getState).post('/api/v1/reports', params).then(response => { + api().post('/api/v1/reports', params).then(response => { dispatch(submitReportSuccess(response.data)); if (onSuccess) onSuccess(); }).catch(error => { diff --git a/app/javascript/flavours/glitch/actions/search.js b/app/javascript/flavours/glitch/actions/search.js index 44344e2fb5..849fc6d33c 100644 --- a/app/javascript/flavours/glitch/actions/search.js +++ b/app/javascript/flavours/glitch/actions/search.js @@ -46,7 +46,7 @@ export function submitSearch(type) { dispatch(fetchSearchRequest(type)); - api(getState).get('/api/v2/search', { + api().get('/api/v2/search', { params: { q: value, resolve: signedIn, @@ -99,7 +99,7 @@ export const expandSearch = type => (dispatch, getState) => { dispatch(expandSearchRequest(type)); - api(getState).get('/api/v2/search', { + api().get('/api/v2/search', { params: { q: value, type, @@ -156,7 +156,7 @@ export const openURL = (value, history, onFailure) => (dispatch, getState) => { dispatch(fetchSearchRequest()); - api(getState).get('/api/v2/search', { params: { q: value, resolve: true } }).then(response => { + api().get('/api/v2/search', { params: { q: value, resolve: true } }).then(response => { if (response.data.accounts?.length > 0) { dispatch(importFetchedAccounts(response.data.accounts)); history.push(`/@${response.data.accounts[0].acct}`); diff --git a/app/javascript/flavours/glitch/actions/server.js b/app/javascript/flavours/glitch/actions/server.js index 65f3efc3a7..32ee093afa 100644 --- a/app/javascript/flavours/glitch/actions/server.js +++ b/app/javascript/flavours/glitch/actions/server.js @@ -25,7 +25,7 @@ export const fetchServer = () => (dispatch, getState) => { dispatch(fetchServerRequest()); - api(getState) + api() .get('/api/v2/instance').then(({ data }) => { if (data.contact.account) dispatch(importFetchedAccount(data.contact.account)); dispatch(fetchServerSuccess(data)); @@ -46,10 +46,10 @@ const fetchServerFail = error => ({ error, }); -export const fetchServerTranslationLanguages = () => (dispatch, getState) => { +export const fetchServerTranslationLanguages = () => (dispatch) => { dispatch(fetchServerTranslationLanguagesRequest()); - api(getState) + api() .get('/api/v1/instance/translation_languages').then(({ data }) => { dispatch(fetchServerTranslationLanguagesSuccess(data)); }).catch(err => dispatch(fetchServerTranslationLanguagesFail(err))); @@ -76,7 +76,7 @@ export const fetchExtendedDescription = () => (dispatch, getState) => { dispatch(fetchExtendedDescriptionRequest()); - api(getState) + api() .get('/api/v1/instance/extended_description') .then(({ data }) => dispatch(fetchExtendedDescriptionSuccess(data))) .catch(err => dispatch(fetchExtendedDescriptionFail(err))); @@ -103,7 +103,7 @@ export const fetchDomainBlocks = () => (dispatch, getState) => { dispatch(fetchDomainBlocksRequest()); - api(getState) + api() .get('/api/v1/instance/domain_blocks') .then(({ data }) => dispatch(fetchDomainBlocksSuccess(true, data))) .catch(err => { diff --git a/app/javascript/flavours/glitch/actions/statuses.js b/app/javascript/flavours/glitch/actions/statuses.js index 332057ee67..c4d292567d 100644 --- a/app/javascript/flavours/glitch/actions/statuses.js +++ b/app/javascript/flavours/glitch/actions/statuses.js @@ -59,7 +59,7 @@ export function fetchStatus(id, forceFetch = false) { dispatch(fetchStatusRequest(id, skipLoading)); - api(getState).get(`/api/v1/statuses/${id}`).then(response => { + api().get(`/api/v1/statuses/${id}`).then(response => { dispatch(importFetchedStatus(response.data)); dispatch(fetchStatusSuccess(skipLoading)); }).catch(error => { @@ -103,7 +103,7 @@ export const editStatus = (id, routerHistory) => (dispatch, getState) => { dispatch(fetchStatusSourceRequest()); - api(getState).get(`/api/v1/statuses/${id}/source`).then(response => { + api().get(`/api/v1/statuses/${id}/source`).then(response => { dispatch(fetchStatusSourceSuccess()); ensureComposeIsVisible(getState, routerHistory); dispatch(setComposeToStatus(status, response.data.text, response.data.spoiler_text, response.data.content_type)); @@ -135,7 +135,7 @@ export function deleteStatus(id, routerHistory, withRedraft = false) { dispatch(deleteStatusRequest(id)); - api(getState).delete(`/api/v1/statuses/${id}`).then(response => { + api().delete(`/api/v1/statuses/${id}`).then(response => { dispatch(deleteStatusSuccess(id)); dispatch(deleteFromTimelines(id)); dispatch(importFetchedAccount(response.data.account)); @@ -176,10 +176,10 @@ export const updateStatus = status => dispatch => dispatch(importFetchedStatus(status)); export function fetchContext(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchContextRequest(id)); - api(getState).get(`/api/v1/statuses/${id}/context`).then(response => { + api().get(`/api/v1/statuses/${id}/context`).then(response => { dispatch(importFetchedStatuses(response.data.ancestors.concat(response.data.descendants))); dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants)); @@ -220,10 +220,10 @@ export function fetchContextFail(id, error) { } export function muteStatus(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(muteStatusRequest(id)); - api(getState).post(`/api/v1/statuses/${id}/mute`).then(() => { + api().post(`/api/v1/statuses/${id}/mute`).then(() => { dispatch(muteStatusSuccess(id)); }).catch(error => { dispatch(muteStatusFail(id, error)); @@ -254,10 +254,10 @@ export function muteStatusFail(id, error) { } export function unmuteStatus(id) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(unmuteStatusRequest(id)); - api(getState).post(`/api/v1/statuses/${id}/unmute`).then(() => { + api().post(`/api/v1/statuses/${id}/unmute`).then(() => { dispatch(unmuteStatusSuccess(id)); }).catch(error => { dispatch(unmuteStatusFail(id, error)); @@ -317,10 +317,10 @@ export function toggleStatusCollapse(id, isCollapsed) { }; } -export const translateStatus = id => (dispatch, getState) => { +export const translateStatus = id => (dispatch) => { dispatch(translateStatusRequest(id)); - api(getState).post(`/api/v1/statuses/${id}/translate`).then(response => { + api().post(`/api/v1/statuses/${id}/translate`).then(response => { dispatch(translateStatusSuccess(id, response.data)); }).catch(error => { dispatch(translateStatusFail(id, error)); diff --git a/app/javascript/flavours/glitch/actions/suggestions.js b/app/javascript/flavours/glitch/actions/suggestions.js index 8eafe38b21..258ffa901d 100644 --- a/app/javascript/flavours/glitch/actions/suggestions.js +++ b/app/javascript/flavours/glitch/actions/suggestions.js @@ -10,10 +10,10 @@ export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL'; export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS'; export function fetchSuggestions(withRelationships = false) { - return (dispatch, getState) => { + return (dispatch) => { dispatch(fetchSuggestionsRequest()); - api(getState).get('/api/v2/suggestions', { params: { limit: 20 } }).then(response => { + api().get('/api/v2/suggestions', { params: { limit: 20 } }).then(response => { dispatch(importFetchedAccounts(response.data.map(x => x.account))); dispatch(fetchSuggestionsSuccess(response.data)); @@ -48,11 +48,11 @@ export function fetchSuggestionsFail(error) { }; } -export const dismissSuggestion = accountId => (dispatch, getState) => { +export const dismissSuggestion = accountId => (dispatch) => { dispatch({ type: SUGGESTIONS_DISMISS, id: accountId, }); - api(getState).delete(`/api/v1/suggestions/${accountId}`).catch(() => {}); + api().delete(`/api/v1/suggestions/${accountId}`).catch(() => {}); }; diff --git a/app/javascript/flavours/glitch/actions/tags.js b/app/javascript/flavours/glitch/actions/tags.js index dda8c924bb..d18d7e514f 100644 --- a/app/javascript/flavours/glitch/actions/tags.js +++ b/app/javascript/flavours/glitch/actions/tags.js @@ -20,10 +20,10 @@ export const HASHTAG_UNFOLLOW_REQUEST = 'HASHTAG_UNFOLLOW_REQUEST'; export const HASHTAG_UNFOLLOW_SUCCESS = 'HASHTAG_UNFOLLOW_SUCCESS'; export const HASHTAG_UNFOLLOW_FAIL = 'HASHTAG_UNFOLLOW_FAIL'; -export const fetchHashtag = name => (dispatch, getState) => { +export const fetchHashtag = name => (dispatch) => { dispatch(fetchHashtagRequest()); - api(getState).get(`/api/v1/tags/${name}`).then(({ data }) => { + api().get(`/api/v1/tags/${name}`).then(({ data }) => { dispatch(fetchHashtagSuccess(name, data)); }).catch(err => { dispatch(fetchHashtagFail(err)); @@ -45,10 +45,10 @@ export const fetchHashtagFail = error => ({ error, }); -export const fetchFollowedHashtags = () => (dispatch, getState) => { +export const fetchFollowedHashtags = () => (dispatch) => { dispatch(fetchFollowedHashtagsRequest()); - api(getState).get('/api/v1/followed_tags').then(response => { + api().get('/api/v1/followed_tags').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(fetchFollowedHashtagsSuccess(response.data, next ? next.uri : null)); }).catch(err => { @@ -87,7 +87,7 @@ export function expandFollowedHashtags() { dispatch(expandFollowedHashtagsRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(expandFollowedHashtagsSuccess(response.data, next ? next.uri : null)); }).catch(error => { @@ -117,10 +117,10 @@ export function expandFollowedHashtagsFail(error) { }; } -export const followHashtag = name => (dispatch, getState) => { +export const followHashtag = name => (dispatch) => { dispatch(followHashtagRequest(name)); - api(getState).post(`/api/v1/tags/${name}/follow`).then(({ data }) => { + api().post(`/api/v1/tags/${name}/follow`).then(({ data }) => { dispatch(followHashtagSuccess(name, data)); }).catch(err => { dispatch(followHashtagFail(name, err)); @@ -144,10 +144,10 @@ export const followHashtagFail = (name, error) => ({ error, }); -export const unfollowHashtag = name => (dispatch, getState) => { +export const unfollowHashtag = name => (dispatch) => { dispatch(unfollowHashtagRequest(name)); - api(getState).post(`/api/v1/tags/${name}/unfollow`).then(({ data }) => { + api().post(`/api/v1/tags/${name}/unfollow`).then(({ data }) => { dispatch(unfollowHashtagSuccess(name, data)); }).catch(err => { dispatch(unfollowHashtagFail(name, err)); diff --git a/app/javascript/flavours/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js index 980b4af66d..1fa2c3cde4 100644 --- a/app/javascript/flavours/glitch/actions/timelines.js +++ b/app/javascript/flavours/glitch/actions/timelines.js @@ -125,7 +125,7 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) { dispatch(expandTimelineRequest(timelineId, isLoadingMore)); - api(getState).get(path, { params }).then(response => { + api().get(path, { params }).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); diff --git a/app/javascript/flavours/glitch/actions/trends.js b/app/javascript/flavours/glitch/actions/trends.js index d314423884..0b840b41ce 100644 --- a/app/javascript/flavours/glitch/actions/trends.js +++ b/app/javascript/flavours/glitch/actions/trends.js @@ -18,10 +18,10 @@ export const TRENDS_STATUSES_EXPAND_REQUEST = 'TRENDS_STATUSES_EXPAND_REQUEST'; export const TRENDS_STATUSES_EXPAND_SUCCESS = 'TRENDS_STATUSES_EXPAND_SUCCESS'; export const TRENDS_STATUSES_EXPAND_FAIL = 'TRENDS_STATUSES_EXPAND_FAIL'; -export const fetchTrendingHashtags = () => (dispatch, getState) => { +export const fetchTrendingHashtags = () => (dispatch) => { dispatch(fetchTrendingHashtagsRequest()); - api(getState) + api() .get('/api/v1/trends/tags') .then(({ data }) => dispatch(fetchTrendingHashtagsSuccess(data))) .catch(err => dispatch(fetchTrendingHashtagsFail(err))); @@ -45,10 +45,10 @@ export const fetchTrendingHashtagsFail = error => ({ skipAlert: true, }); -export const fetchTrendingLinks = () => (dispatch, getState) => { +export const fetchTrendingLinks = () => (dispatch) => { dispatch(fetchTrendingLinksRequest()); - api(getState) + api() .get('/api/v1/trends/links') .then(({ data }) => dispatch(fetchTrendingLinksSuccess(data))) .catch(err => dispatch(fetchTrendingLinksFail(err))); @@ -79,7 +79,7 @@ export const fetchTrendingStatuses = () => (dispatch, getState) => { dispatch(fetchTrendingStatusesRequest()); - api(getState).get('/api/v1/trends/statuses').then(response => { + api().get('/api/v1/trends/statuses').then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(fetchTrendingStatusesSuccess(response.data, next ? next.uri : null)); @@ -115,7 +115,7 @@ export const expandTrendingStatuses = () => (dispatch, getState) => { dispatch(expandTrendingStatusesRequest()); - api(getState).get(url).then(response => { + api().get(url).then(response => { const next = getLinks(response).refs.find(link => link.rel === 'next'); dispatch(importFetchedStatuses(response.data)); dispatch(expandTrendingStatusesSuccess(response.data, next ? next.uri : null)); diff --git a/app/javascript/flavours/glitch/api.ts b/app/javascript/flavours/glitch/api.ts index de597a3e3b..ccff68c373 100644 --- a/app/javascript/flavours/glitch/api.ts +++ b/app/javascript/flavours/glitch/api.ts @@ -2,8 +2,8 @@ import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios'; import axios from 'axios'; import LinkHeader from 'http-link-header'; +import { getAccessToken } from './initial_state'; import ready from './ready'; -import type { GetState } from './store'; export const getLinks = (response: AxiosResponse) => { const value = response.headers.link as string | undefined; @@ -29,30 +29,22 @@ const setCSRFHeader = () => { void ready(setCSRFHeader); -export const authorizationTokenFromState = (getState?: GetState) => { - return ( - getState && (getState().meta.get('access_token', '') as string | false) - ); -}; +const authorizationTokenFromInitialState = (): RawAxiosRequestHeaders => { + const accessToken = getAccessToken(); -const authorizationHeaderFromState = (getState?: GetState) => { - const accessToken = authorizationTokenFromState(getState); - - if (!accessToken) { - return {}; - } + if (!accessToken) return {}; return { Authorization: `Bearer ${accessToken}`, - } as RawAxiosRequestHeaders; + }; }; // eslint-disable-next-line import/no-default-export -export default function api(getState: GetState) { +export default function api() { return axios.create({ headers: { ...csrfHeader, - ...authorizationHeaderFromState(getState), + ...authorizationTokenFromInitialState(), }, transformResponse: [ diff --git a/app/javascript/flavours/glitch/identity_context.tsx b/app/javascript/flavours/glitch/identity_context.tsx index 28dcb1f14b..42d1b6c475 100644 --- a/app/javascript/flavours/glitch/identity_context.tsx +++ b/app/javascript/flavours/glitch/identity_context.tsx @@ -9,7 +9,6 @@ export interface IdentityContextType { signedIn: boolean; accountId: string | undefined; disabledAccountId: string | undefined; - accessToken: string | undefined; permissions: number; } @@ -17,14 +16,12 @@ export const identityContextPropShape = PropTypes.shape({ signedIn: PropTypes.bool.isRequired, accountId: PropTypes.string, disabledAccountId: PropTypes.string, - accessToken: PropTypes.string, }).isRequired; export const createIdentityContext = (state: InitialState) => ({ signedIn: !!state.meta.me, accountId: state.meta.me, disabledAccountId: state.meta.disabled_account_id, - accessToken: state.meta.access_token, permissions: state.role?.permissions ?? 0, }); @@ -33,7 +30,6 @@ export const IdentityContext = createContext({ permissions: 0, accountId: undefined, disabledAccountId: undefined, - accessToken: undefined, }); export const useIdentity = () => useContext(IdentityContext); diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index 1a40810418..4492813fd3 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -143,4 +143,11 @@ export const pollLimits = (initialState && initialState.poll_limits); export const defaultContentType = getMeta('default_content_type'); export const useSystemEmojiFont = getMeta('system_emoji_font'); +/** + * @returns {string | undefined} + */ +export function getAccessToken() { + return getMeta('access_token'); +} + export default initialState; diff --git a/app/javascript/flavours/glitch/reducers/meta.js b/app/javascript/flavours/glitch/reducers/meta.js index 1fc669375c..d729924099 100644 --- a/app/javascript/flavours/glitch/reducers/meta.js +++ b/app/javascript/flavours/glitch/reducers/meta.js @@ -6,7 +6,6 @@ import { layoutFromWindow } from 'flavours/glitch/is_mobile'; const initialState = ImmutableMap({ streaming_api_base_url: null, - access_token: null, layout: layoutFromWindow(), permissions: '0', }); @@ -14,7 +13,8 @@ const initialState = ImmutableMap({ export default function meta(state = initialState, action) { switch(action.type) { case STORE_HYDRATE: - return state.merge(action.state.get('meta')).set('permissions', action.state.getIn(['role', 'permissions'])); + // we do not want `access_token` to be stored in the state + return state.merge(action.state.get('meta')).delete('access_token').set('permissions', action.state.getIn(['role', 'permissions'])); case changeLayout.type: return state.set('layout', action.payload.layout); default: diff --git a/app/javascript/flavours/glitch/stream.js b/app/javascript/flavours/glitch/stream.js index ff3af5fd88..40d69136a8 100644 --- a/app/javascript/flavours/glitch/stream.js +++ b/app/javascript/flavours/glitch/stream.js @@ -2,6 +2,8 @@ import WebSocketClient from '@gamestdio/websocket'; +import { getAccessToken } from './initial_state'; + /** * @type {WebSocketClient | undefined} */ @@ -145,9 +147,11 @@ const channelNameWithInlineParams = (channelName, params) => { // @ts-expect-error export const connectStream = (channelName, params, callbacks) => (dispatch, getState) => { const streamingAPIBaseURL = getState().getIn(['meta', 'streaming_api_base_url']); - const accessToken = getState().getIn(['meta', 'access_token']); + const accessToken = getAccessToken(); const { onConnect, onReceive, onDisconnect } = callbacks(dispatch, getState); + if(!accessToken) throw new Error("Trying to connect to the streaming server but no access token is available."); + // If we cannot use a websockets connection, we must fall back // to using individual connections for each channel if (!streamingAPIBaseURL.startsWith('ws')) { diff --git a/app/javascript/flavours/glitch/test_helpers.tsx b/app/javascript/flavours/glitch/test_helpers.tsx index 69d57b95a0..09efda1e73 100644 --- a/app/javascript/flavours/glitch/test_helpers.tsx +++ b/app/javascript/flavours/glitch/test_helpers.tsx @@ -17,7 +17,6 @@ class FakeIdentityWrapper extends Component< signedIn: PropTypes.bool.isRequired, accountId: PropTypes.string, disabledAccountId: PropTypes.string, - accessToken: PropTypes.string, }).isRequired, }; @@ -26,7 +25,6 @@ class FakeIdentityWrapper extends Component< identity: { signedIn: this.props.signedIn, accountId: '123', - accessToken: 'test-access-token', }, }; } From 15d307075479cf93ea199be0f25820003ddbe27c Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 23 May 2024 09:30:48 +0200 Subject: [PATCH 224/658] Fix some API calls that should not use an API token (#30401) --- app/javascript/mastodon/api.ts | 4 ++-- app/javascript/mastodon/components/admin/Counter.jsx | 2 +- app/javascript/mastodon/components/admin/Dimension.jsx | 2 +- app/javascript/mastodon/components/admin/ImpactReport.jsx | 2 +- .../mastodon/components/admin/ReportReasonSelector.jsx | 4 ++-- app/javascript/mastodon/components/admin/Retention.jsx | 2 +- app/javascript/mastodon/components/admin/Trends.jsx | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/javascript/mastodon/api.ts b/app/javascript/mastodon/api.ts index ccff68c373..2ccf178f00 100644 --- a/app/javascript/mastodon/api.ts +++ b/app/javascript/mastodon/api.ts @@ -40,11 +40,11 @@ const authorizationTokenFromInitialState = (): RawAxiosRequestHeaders => { }; // eslint-disable-next-line import/no-default-export -export default function api() { +export default function api(withAuthorization = true) { return axios.create({ headers: { ...csrfHeader, - ...authorizationTokenFromInitialState(), + ...(withAuthorization ? authorizationTokenFromInitialState() : {}), }, transformResponse: [ diff --git a/app/javascript/mastodon/components/admin/Counter.jsx b/app/javascript/mastodon/components/admin/Counter.jsx index 6ce23c9f05..e4d21da627 100644 --- a/app/javascript/mastodon/components/admin/Counter.jsx +++ b/app/javascript/mastodon/components/admin/Counter.jsx @@ -48,7 +48,7 @@ export default class Counter extends PureComponent { componentDidMount () { const { measure, start_at, end_at, params } = this.props; - api().post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => { + api(false).post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => { this.setState({ loading: false, data: res.data, diff --git a/app/javascript/mastodon/components/admin/Dimension.jsx b/app/javascript/mastodon/components/admin/Dimension.jsx index bfda6c93d7..56557ad8e8 100644 --- a/app/javascript/mastodon/components/admin/Dimension.jsx +++ b/app/javascript/mastodon/components/admin/Dimension.jsx @@ -26,7 +26,7 @@ export default class Dimension extends PureComponent { componentDidMount () { const { start_at, end_at, dimension, limit, params } = this.props; - api().post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => { + api(false).post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => { this.setState({ loading: false, data: res.data, diff --git a/app/javascript/mastodon/components/admin/ImpactReport.jsx b/app/javascript/mastodon/components/admin/ImpactReport.jsx index c27ee0ab08..add54134b6 100644 --- a/app/javascript/mastodon/components/admin/ImpactReport.jsx +++ b/app/javascript/mastodon/components/admin/ImpactReport.jsx @@ -27,7 +27,7 @@ export default class ImpactReport extends PureComponent { include_subdomains: true, }; - api().post('/api/v1/admin/measures', { + api(false).post('/api/v1/admin/measures', { keys: ['instance_accounts', 'instance_follows', 'instance_followers'], start_at: null, end_at: null, diff --git a/app/javascript/mastodon/components/admin/ReportReasonSelector.jsx b/app/javascript/mastodon/components/admin/ReportReasonSelector.jsx index 90f4334a6e..cc05e5c163 100644 --- a/app/javascript/mastodon/components/admin/ReportReasonSelector.jsx +++ b/app/javascript/mastodon/components/admin/ReportReasonSelector.jsx @@ -105,7 +105,7 @@ class ReportReasonSelector extends PureComponent { }; componentDidMount() { - api().get('/api/v1/instance').then(res => { + api(false).get('/api/v1/instance').then(res => { this.setState({ rules: res.data.rules, }); @@ -122,7 +122,7 @@ class ReportReasonSelector extends PureComponent { return; } - api().put(`/api/v1/admin/reports/${id}`, { + api(false).put(`/api/v1/admin/reports/${id}`, { category, rule_ids: category === 'violation' ? rule_ids : [], }).catch(err => { diff --git a/app/javascript/mastodon/components/admin/Retention.jsx b/app/javascript/mastodon/components/admin/Retention.jsx index 1e8ef48b7a..87746e9f49 100644 --- a/app/javascript/mastodon/components/admin/Retention.jsx +++ b/app/javascript/mastodon/components/admin/Retention.jsx @@ -34,7 +34,7 @@ export default class Retention extends PureComponent { componentDidMount () { const { start_at, end_at, frequency } = this.props; - api().post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => { + api(false).post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => { this.setState({ loading: false, data: res.data, diff --git a/app/javascript/mastodon/components/admin/Trends.jsx b/app/javascript/mastodon/components/admin/Trends.jsx index c69b4a8cba..fd6db106d5 100644 --- a/app/javascript/mastodon/components/admin/Trends.jsx +++ b/app/javascript/mastodon/components/admin/Trends.jsx @@ -22,7 +22,7 @@ export default class Trends extends PureComponent { componentDidMount () { const { limit } = this.props; - api().get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => { + api(false).get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => { this.setState({ loading: false, data: res.data, From 5b5a35cf96de51b5ef44f69dcde1e3dc2acb9dd6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 10:26:29 +0200 Subject: [PATCH 225/658] New Crowdin Translations (automated) (#30402) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/be.json | 1 + app/javascript/mastodon/locales/lv.json | 2 +- config/locales/an.yml | 1 - config/locales/ar.yml | 1 - config/locales/ast.yml | 2 - config/locales/be.yml | 1 - config/locales/bg.yml | 2 +- config/locales/ca.yml | 2 +- config/locales/ckb.yml | 1 - config/locales/co.yml | 1 - config/locales/cs.yml | 1 - config/locales/cy.yml | 3 +- config/locales/da.yml | 2 +- config/locales/de.yml | 2 +- config/locales/devise.lt.yml | 2 +- config/locales/el.yml | 1 - config/locales/en-GB.yml | 1 - config/locales/eo.yml | 1 - config/locales/es-AR.yml | 2 +- config/locales/es-MX.yml | 2 +- config/locales/es.yml | 2 +- config/locales/et.yml | 1 - config/locales/eu.yml | 1 - config/locales/fa.yml | 1 - config/locales/fi.yml | 1 - config/locales/fo.yml | 2 +- config/locales/fr-CA.yml | 1 - config/locales/fr.yml | 1 - config/locales/fy.yml | 1 - config/locales/gd.yml | 1 - config/locales/gl.yml | 2 +- config/locales/he.yml | 2 +- config/locales/hu.yml | 2 +- config/locales/ia.yml | 2 +- config/locales/id.yml | 1 - config/locales/ie.yml | 1 - config/locales/io.yml | 1 - config/locales/is.yml | 2 +- config/locales/it.yml | 2 +- config/locales/ja.yml | 1 - config/locales/kk.yml | 1 - config/locales/ko.yml | 2 +- config/locales/ku.yml | 1 - config/locales/lad.yml | 1 - config/locales/lt.yml | 148 ++++++++++++++++++++---- config/locales/lv.yml | 1 - config/locales/ms.yml | 1 - config/locales/my.yml | 1 - config/locales/nl.yml | 2 +- config/locales/nn.yml | 1 - config/locales/no.yml | 1 - config/locales/oc.yml | 1 - config/locales/pl.yml | 2 +- config/locales/pt-BR.yml | 1 - config/locales/pt-PT.yml | 2 +- config/locales/ru.yml | 1 - config/locales/sc.yml | 1 - config/locales/sco.yml | 1 - config/locales/si.yml | 1 - config/locales/simple_form.lt.yml | 7 ++ config/locales/simple_form.nl.yml | 4 +- config/locales/simple_form.sr-Latn.yml | 10 +- config/locales/simple_form.sr.yml | 12 +- config/locales/sk.yml | 1 - config/locales/sl.yml | 2 +- config/locales/sq.yml | 3 +- config/locales/sr-Latn.yml | 8 +- config/locales/sr.yml | 8 +- config/locales/sv.yml | 1 - config/locales/th.yml | 1 - config/locales/tr.yml | 2 +- config/locales/uk.yml | 1 - config/locales/vi.yml | 1 - config/locales/zh-CN.yml | 2 +- config/locales/zh-HK.yml | 1 - config/locales/zh-TW.yml | 2 +- 76 files changed, 182 insertions(+), 113 deletions(-) diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 2b7673312f..61e96e4b58 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -469,6 +469,7 @@ "notification.follow": "{name} падпісаўся на вас", "notification.follow_request": "{name} адправіў запыт на падпіску", "notification.mention": "{name} згадаў вас", + "notification.moderation-warning.learn_more": "Даведацца больш", "notification.own_poll": "Ваша апытанне скончылася", "notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася", "notification.reblog": "{name} пашырыў ваш допіс", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index e7ab114909..b61a2c0c36 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -491,7 +491,7 @@ "onboarding.actions.go_to_home": "Dodieties uz manu mājas plūsmu", "onboarding.compose.template": "Sveiki, #Mastodon!", "onboarding.follows.empty": "Diemžēl pašlaik nevar parādīt rezultātus. Vari mēģināt izmantot meklēšanu vai pārlūkot izpētes lapu, lai atrastu cilvēkus, kuriem sekot, vai vēlāk mēģināt vēlreiz.", - "onboarding.follows.lead": "Tava mājas plūsma ir galvenais veids, kā izbaudīt Mastodon. Jo vairāk cilvēku sekosi, jo aktīvāk un interesantāk tas būs. Lai sāktu, šeit ir daži ieteikumi:", + "onboarding.follows.lead": "Tava mājas plūsma ir galvenais veids, kā pieredzēt Mastodon. Jo vairāk cilvēkiem sekosi, jo dzīvīgāka un aizraujošāka tā būs. Lai sāktu, šeit ir daži ieteikumi:", "onboarding.follows.title": "Pielāgo savu mājas barotni", "onboarding.profile.discoverable": "Padarīt manu profilu atklājamu", "onboarding.profile.display_name": "Attēlojamais vārds", diff --git a/config/locales/an.yml b/config/locales/an.yml index 068a20187d..637aa8c8b3 100644 --- a/config/locales/an.yml +++ b/config/locales/an.yml @@ -852,7 +852,6 @@ an: delete: Borrar edit_preset: Editar aviso predeterminau empty: Encara no has definiu garra preajuste d'alvertencia. - title: Editar configuración predeterminada d'avisos webhooks: add_new: Anyadir endpoint delete: Eliminar diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 02ba56d0b2..2ca7538c32 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -1013,7 +1013,6 @@ ar: delete: حذف edit_preset: تعديل نموذج التحذير empty: لم تحدد أي إعدادات تحذير مسبقة بعد. - title: إدارة نماذج التحذير webhooks: add_new: إضافة نقطة نهاية delete: حذف diff --git a/config/locales/ast.yml b/config/locales/ast.yml index 816858d4a0..9e6ec6d233 100644 --- a/config/locales/ast.yml +++ b/config/locales/ast.yml @@ -400,8 +400,6 @@ ast: usable: Pue usase title: Tendencies trending: En tendencia - warning_presets: - title: Xestión d'alvertencies preconfiguraes webhooks: add_new: Amestar un estremu delete: Desaniciar diff --git a/config/locales/be.yml b/config/locales/be.yml index 13daa9897e..6f1f189523 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -983,7 +983,6 @@ be: delete: Выдаліць edit_preset: Рэдагаваць шаблон папярэджання empty: Вы яшчэ не вызначылі ніякіх шаблонаў папярэджанняў. - title: Кіраванне шаблонамі папярэджанняў webhooks: add_new: Дадаць канцавую кропку delete: Выдаліць diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 51180bc66f..5aca8ad0fd 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -951,7 +951,7 @@ bg: delete: Изтриване edit_preset: Редакция на предварителните настройки empty: Все още няма предварителни настройки за предупрежденията. - title: Управление на предварителните настройки + title: Предупредителни образци webhooks: add_new: Добавяне на крайна точка delete: Изтриване diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 34fd900851..ec32f771e9 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -951,7 +951,7 @@ ca: delete: Elimina edit_preset: Edita l'avís predeterminat empty: Encara no has definit cap preavís. - title: Gestiona les configuracions predefinides dels avisos + title: Predefinicions d'avís webhooks: add_new: Afegir extrem delete: Elimina diff --git a/config/locales/ckb.yml b/config/locales/ckb.yml index dfa035eca8..93eea8273f 100644 --- a/config/locales/ckb.yml +++ b/config/locales/ckb.yml @@ -548,7 +548,6 @@ ckb: add_new: زیادکردنی نوێ delete: سڕینەوە edit_preset: دەستکاریکردنی ئاگاداری پێشگریمان - title: بەڕێوەبردنی ئاگادارکردنەوە پێش‌سازدان admin_mailer: new_pending_account: body: وردەکاریهەژمارە نوێیەکە لە خوارەوەیە. دەتوانیت ئەم نەرمەکالا پەسەند بکەیت یان ڕەت بکەیتەوە. diff --git a/config/locales/co.yml b/config/locales/co.yml index 7d8abcd112..6edbbc95ff 100644 --- a/config/locales/co.yml +++ b/config/locales/co.yml @@ -510,7 +510,6 @@ co: add_new: Aghjunghje delete: Sguassà edit_preset: Cambià a preselezzione d'avertimentu - title: Amministrà e preselezzione d'avertimentu admin_mailer: new_pending_account: body: I ditagli di u novu contu sò quì sottu. Pudete appruvà o righjittà a dumanda. diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 5693077319..17c743f1de 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -984,7 +984,6 @@ cs: delete: Smazat edit_preset: Upravit předlohu pro varování empty: Zatím jste nedefinovali žádné předlohy varování. - title: Spravovat předlohy pro varování webhooks: add_new: Přidat koncový bod delete: Smazat diff --git a/config/locales/cy.yml b/config/locales/cy.yml index f96068f212..35ed5ade8a 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -297,6 +297,7 @@ cy: update_custom_emoji_html: Mae %{name} wedi diweddaru emoji %{target} update_domain_block_html: Mae %{name} wedi diweddaru bloc parth %{target} update_ip_block_html: Mae %{name} wedi newid rheol IP %{target} + update_report_html: Mae %{name} wedi diweddaru adroddiad %{target} update_status_html: Mae %{name} wedi diweddaru postiad gan %{target} update_user_role_html: Mae %{name} wedi newid rôl %{target} deleted_account: cyfrif wedi'i ddileu @@ -1018,7 +1019,7 @@ cy: delete: Dileu edit_preset: Golygu rhagosodiad rhybudd empty: Nid ydych wedi diffinio unrhyw ragosodiadau rhybudd eto. - title: Rheoli rhagosodiadau rhybudd + title: Rhagosodiadau rhybuddion webhooks: add_new: Ychwanegu diweddbwynt delete: Dileu diff --git a/config/locales/da.yml b/config/locales/da.yml index 17d3037a75..f37086264f 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -951,7 +951,7 @@ da: delete: Slet edit_preset: Redigér advarselsforvalg empty: Ingen advarselsforvalg defineret endnu. - title: Håndtérr advarselsforvalg + title: Præindstillinger for advarsel webhooks: add_new: Tilføj endepunkt delete: Slet diff --git a/config/locales/de.yml b/config/locales/de.yml index dd2129584f..11460c3b40 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -951,7 +951,7 @@ de: delete: Löschen edit_preset: Warnvorlage bearbeiten empty: Du hast noch keine Warnvorlagen hinzugefügt. - title: Warnvorlagen verwalten + title: Warnvorlagen webhooks: add_new: Endpunkt hinzufügen delete: Löschen diff --git a/config/locales/devise.lt.yml b/config/locales/devise.lt.yml index ec5b852727..e36e60a758 100644 --- a/config/locales/devise.lt.yml +++ b/config/locales/devise.lt.yml @@ -22,7 +22,7 @@ lt: action: Patvirtinti el. pašto adresą action_with_app: Patvirtinti ir grįžti į %{app} explanation: Šiuo el. pašto adresu sukūrei paskyrą %{host}. Iki jos aktyvavimo liko vienas paspaudimas. Jei tai buvo ne tu, ignoruok šį el. laišką. - explanation_when_pending: Šiuo el. pašto adresu pateikei paraišką pakvietimui į %{host}. Kai patvirtinsi savo el. pašto adresą, mes peržiūrėsime tavo paraišką. Gali prisijungti ir pakeisti savo duomenis arba ištrinti paskyrą, tačiau negalėsi naudotis daugeliu funkcijų, kol tavo paskyra nebus patvirtinta. Jei tavo paraiška bus atmesta, duomenys bus pašalinti, todėl jokių papildomų veiksmų iš tavęs nereikės. Jei tai buvo ne tu, ignoruok šį el. laišką. + explanation_when_pending: Šiuo el. pašto adresu pateikei paraišką pakvietimui į %{host}. Kai patvirtinsi savo el. pašto adresą, mes peržiūrėsime tavo paraišką. Gali prisijungti ir pakeisti savo duomenis arba ištrinti paskyrą, bet negalėsi naudotis daugeliu funkcijų, kol tavo paskyra nebus patvirtinta. Jei tavo paraiška bus atmesta, duomenys bus pašalinti, todėl jokių papildomų veiksmų iš tavęs nereikės. Jei tai buvo ne tu, ignoruok šį el. laišką. extra_html: Taip pat peržiūrėk serverio taisykles ir mūsų paslaugų teikimo sąlygas. subject: 'Mastodon: patvirtinimo instrukcijos %{instance}' title: Patvirtinti el. pašto adresą diff --git a/config/locales/el.yml b/config/locales/el.yml index 2e7ac87463..47b2250f0e 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -903,7 +903,6 @@ el: delete: Διαγραφή edit_preset: Ενημέρωση προκαθορισμένης προειδοποίησης empty: Δεν έχετε ακόμη ορίσει κάποια προκαθορισμένη προειδοποίηση. - title: Διαχείριση προκαθορισμένων προειδοποιήσεων webhooks: add_new: Προσθήκη σημείου τερματισμού delete: Διαγραφή diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 7cd888b373..07eb84ebbe 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -950,7 +950,6 @@ en-GB: delete: Delete edit_preset: Edit warning preset empty: You haven't defined any warning presets yet. - title: Warning presets webhooks: add_new: Add endpoint delete: Delete diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 749f80687d..95e3dd5a8d 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -919,7 +919,6 @@ eo: delete: Forigi edit_preset: Redakti avertan antaŭagordon empty: Vi ankoraŭ ne difinis iun ajn antaŭagordon de averto. - title: Administri avertajn antaŭagordojn webhooks: add_new: Aldoni finpunkton delete: Forigi diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index 302be44112..d6bfb60a19 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -951,7 +951,7 @@ es-AR: delete: Eliminar edit_preset: Editar preajuste de advertencia empty: Aún no ha definido ningún preajuste de advertencia. - title: Administrar preajustes de advertencia + title: Preajustes de advertencia webhooks: add_new: Agregar punto final delete: Eliminar diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index 10806c6b6c..8f4aa183d8 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -951,7 +951,7 @@ es-MX: delete: Borrar edit_preset: Editar aviso predeterminado empty: Aún no has definido ningún preajuste de advertencia. - title: Editar configuración predeterminada de avisos + title: Preajustes de advertencia webhooks: add_new: Añadir endpoint delete: Eliminar diff --git a/config/locales/es.yml b/config/locales/es.yml index 840bc2ce9b..343f6f5a63 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -951,7 +951,7 @@ es: delete: Borrar edit_preset: Editar aviso predeterminado empty: Aún no has definido ningún preajuste de advertencia. - title: Editar configuración predeterminada de avisos + title: Preajustes de advertencia webhooks: add_new: Añadir endpoint delete: Eliminar diff --git a/config/locales/et.yml b/config/locales/et.yml index a544d8063d..172aad25b9 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -949,7 +949,6 @@ et: delete: Kustuta edit_preset: Hoiatuse eelseadistuse muutmine empty: Hoiatuste eelseadeid pole defineeritud. - title: Halda hoiatuste eelseadistusi webhooks: add_new: Lisa lõpp-punkt delete: Kustuta diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 22ca8135d5..67da357e1d 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -952,7 +952,6 @@ eu: delete: Ezabatu edit_preset: Editatu abisu aurre-ezarpena empty: Ez duzu abisu aurrezarpenik definitu oraindik. - title: Kudeatu abisu aurre-ezarpenak webhooks: add_new: Gehitu amaiera-puntua delete: Ezabatu diff --git a/config/locales/fa.yml b/config/locales/fa.yml index d93d2e7d5f..509d69fcba 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -808,7 +808,6 @@ fa: delete: زدودن edit_preset: ویرایش هشدار پیش‌فرض empty: هنز هیچ پیش‌تنظیم هشداری را تعریف نکرده‌اید. - title: مدیریت هشدارهای پیش‌فرض webhooks: add_new: افزودن نقطهٔ پایانی delete: حذف diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 53db0232aa..3a75066d5b 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -951,7 +951,6 @@ fi: delete: Poista edit_preset: Muokkaa varoituksen esiasetusta empty: Et ole vielä määrittänyt yhtäkään varoitusten esiasetusta. - title: Hallitse varoitusten esiasetuksia webhooks: add_new: Lisää päätepiste delete: Poista diff --git a/config/locales/fo.yml b/config/locales/fo.yml index 57caff4d71..0372d3dca3 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -951,7 +951,7 @@ fo: delete: Strika edit_preset: Rætta ávaringar-undanstilling empty: Tú hevur ikki ásett nakrar ávaringar-undanstillingar enn. - title: Stýr ávaringar-undanstillingar + title: Undanstillingar fyri ávaring webhooks: add_new: Legg endapunkt afturat delete: Strika diff --git a/config/locales/fr-CA.yml b/config/locales/fr-CA.yml index 05d6b8864d..f297e8bfde 100644 --- a/config/locales/fr-CA.yml +++ b/config/locales/fr-CA.yml @@ -949,7 +949,6 @@ fr-CA: delete: Supprimer edit_preset: Éditer les avertissements prédéfinis empty: Vous n'avez pas encore créé de paramètres prédéfinis pour les avertissements. - title: Gérer les avertissements prédéfinis webhooks: add_new: Ajouter un point de terminaison delete: Supprimer diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 6ab4208801..33cdcd44cc 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -949,7 +949,6 @@ fr: delete: Supprimer edit_preset: Éditer les avertissements prédéfinis empty: Vous n'avez pas encore créé de paramètres prédéfinis pour les avertissements. - title: Gérer les avertissements prédéfinis webhooks: add_new: Ajouter un point de terminaison delete: Supprimer diff --git a/config/locales/fy.yml b/config/locales/fy.yml index 1f1a27fec4..c8e287732a 100644 --- a/config/locales/fy.yml +++ b/config/locales/fy.yml @@ -949,7 +949,6 @@ fy: delete: Fuortsmite edit_preset: Foarynstelling foar warskôging bewurkje empty: Jo hawwe noch gjin foarynstellingen foar warskôgingen tafoege. - title: Foarynstellingen foar warskôgingen beheare webhooks: add_new: Einpunt tafoegje delete: Fuortsmite diff --git a/config/locales/gd.yml b/config/locales/gd.yml index 70bace05cf..52b25e2854 100644 --- a/config/locales/gd.yml +++ b/config/locales/gd.yml @@ -983,7 +983,6 @@ gd: delete: Sguab às edit_preset: Deasaich rabhadh ro-shuidhichte empty: Cha do mhìnich thu ro-sheataichean rabhaidhean fhathast. - title: Stiùirich na rabhaidhean ro-shuidhichte webhooks: add_new: Cuir puing-dheiridh ris delete: Sguab às diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 2c85dc89ae..a8489e425f 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -951,7 +951,7 @@ gl: delete: Eliminar edit_preset: Editar aviso preestablecido empty: Non definiches os avisos prestablecidos. - title: Xestionar avisos preestablecidos + title: Preestablecidos de advertencia webhooks: add_new: Engadir punto de extremo delete: Eliminar diff --git a/config/locales/he.yml b/config/locales/he.yml index 3613a9f0b3..9088f48218 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -985,7 +985,7 @@ he: delete: למחוק edit_preset: ערוך/י טקסט מוכן מראש לאזהרה empty: לא הגדרת עדיין שום טקסט מוכן מראש לאזהרה. - title: ניהול טקסטים מוכנים מראש לאזהרות + title: תצורת אזהרות webhooks: add_new: הוספת נקודת קצה delete: מחיקה diff --git a/config/locales/hu.yml b/config/locales/hu.yml index dd57830515..d79bca7ff7 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -951,7 +951,7 @@ hu: delete: Törlés edit_preset: Figyelmeztetés szerkesztése empty: Nem definiáltál még egyetlen figyelmeztetést sem. - title: Figyelmeztetések + title: Figyelmeztető szövegek webhooks: add_new: Végpont hozzáadása delete: Törlés diff --git a/config/locales/ia.yml b/config/locales/ia.yml index 8af676454f..f8834136b9 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -951,7 +951,7 @@ ia: delete: Deler edit_preset: Rediger aviso predefinite empty: Tu non ha ancora definite alcun avisos predefinite. - title: Gerer avisos predefinite + title: Predefinitiones de avisos webhooks: add_new: Adder terminal delete: Deler diff --git a/config/locales/id.yml b/config/locales/id.yml index bee282fa83..aae790f481 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -831,7 +831,6 @@ id: delete: Hapus edit_preset: Sunting preset peringatan empty: Anda belum mendefinisikan peringatan apapun. - title: Kelola preset peringatan webhooks: add_new: Tambah titik akhir delete: Hapus diff --git a/config/locales/ie.yml b/config/locales/ie.yml index 473d7b750f..432e7d031b 100644 --- a/config/locales/ie.yml +++ b/config/locales/ie.yml @@ -950,7 +950,6 @@ ie: delete: Deleter edit_preset: Modificar prefiguration de avise empty: Vu ancor ha definit null prefigurationes de avise. - title: Modificar prefigurationes de avise webhooks: add_new: Adjunter punctu terminal delete: Deleter diff --git a/config/locales/io.yml b/config/locales/io.yml index ed0d0d6345..bccdcb3cc5 100644 --- a/config/locales/io.yml +++ b/config/locales/io.yml @@ -928,7 +928,6 @@ io: delete: Efacez edit_preset: Modifikez avertfixito empty: Vu ne fixis irga avertfixito til nun. - title: Jerez avertfixiti webhooks: add_new: Insertez finpunto delete: Efacez diff --git a/config/locales/is.yml b/config/locales/is.yml index 9977752969..75950e572d 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -953,7 +953,7 @@ is: delete: Eyða edit_preset: Breyta forstilltri aðvörun empty: Þú hefur ekki enn skilgreint neinar aðvaranaforstillingar. - title: Sýsla með forstilltar aðvaranir + title: Forstilltar aðvaranir webhooks: add_new: Bæta við endapunkti delete: Eyða diff --git a/config/locales/it.yml b/config/locales/it.yml index 5b75e7af7d..c3389f59c6 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -951,7 +951,7 @@ it: delete: Cancella edit_preset: Modifica avviso predefinito empty: Non hai ancora definito alcun avviso preimpostato. - title: Gestisci avvisi predefiniti + title: Preimpostazioni di avviso webhooks: add_new: Aggiungi endpoint delete: Elimina diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 0712ba380a..6c0fba259c 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -933,7 +933,6 @@ ja: delete: 削除 edit_preset: プリセット警告文を編集 empty: まだプリセット警告文が作成されていません。 - title: プリセット警告文を管理 webhooks: add_new: エンドポイントを追加 delete: 削除 diff --git a/config/locales/kk.yml b/config/locales/kk.yml index f08d8ead1a..2695127f0a 100644 --- a/config/locales/kk.yml +++ b/config/locales/kk.yml @@ -299,7 +299,6 @@ kk: add_new: Add nеw delete: Deletе edit_preset: Edit warning prеset - title: Manage warning presеts admin_mailer: new_pending_account: body: Жаңа есептік жазба туралы мәліметтер төменде берілген. Бұл қолданбаны мақұлдауыңызға немесе қабылдамауыңызға болады. diff --git a/config/locales/ko.yml b/config/locales/ko.yml index b104e31fc0..9de2f6ca53 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -936,7 +936,7 @@ ko: delete: 삭제 edit_preset: 경고 프리셋 편집 empty: 아직 어떤 경고 틀도 정의되지 않았습니다. - title: 경고 틀 관리 + title: 경고 프리셋 webhooks: add_new: 엔드포인트 추가 delete: 삭제 diff --git a/config/locales/ku.yml b/config/locales/ku.yml index 74dcd6f8f3..c24337dd7c 100644 --- a/config/locales/ku.yml +++ b/config/locales/ku.yml @@ -849,7 +849,6 @@ ku: delete: Jê bibe edit_preset: Hişyariyên pêşsazkirî serrast bike empty: Te hin tu hişyariyên pêşsazkirî destnîşan nekirine. - title: Hişyariyên pêşsazkirî bi rêve bibe webhooks: add_new: Xala dawîbûnê tevlî bike delete: Jê bibe diff --git a/config/locales/lad.yml b/config/locales/lad.yml index 9c165472cd..d0657e73f9 100644 --- a/config/locales/lad.yml +++ b/config/locales/lad.yml @@ -950,7 +950,6 @@ lad: delete: Efasa edit_preset: Edita avizo predeterminado empty: Ainda no tienes definido ningun avizo predeterminado. - title: Edita konfigurasyon predeterminada de avizos webhooks: add_new: Adjusta endpoint delete: Efasa diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 3e514a547b..8e32ed07bd 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -451,7 +451,7 @@ lt: filter: all: Visi available: Pasiekiamas - expired: Pasibaigęs + expired: Nebegaliojantis title: Filtras title: Kvietimai relays: @@ -505,9 +505,15 @@ lt: unresolved: Neišspręsti updated_at: Atnaujinti roles: + categories: + invites: Kvietimai everyone: Numatytieji leidimai everyone_full_description_html: Tai – bazinis vaidmuo, turintis įtakos visiems naudotojams, net ir tiems, kurie neturi priskirto vaidmens. Visi kiti vaidmenys iš jo paveldi teises. privileges: + invite_users: Kviesti naudotojus + invite_users_description: Leidžia naudotojams pakviesti naujus žmones į serverį. + manage_invites: Tvarkyti kvietimus + manage_invites_description: Leidžia naudotojams naršyti ir deaktyvuoti kvietimų nuorodas. manage_taxonomies_description: Leidžia naudotojams peržiūrėti tendencingą turinį ir atnaujinti saitažodžių nustatymus settings: captcha_enabled: @@ -522,12 +528,34 @@ lt: registrations: moderation_recommandation: Prieš atidarant registraciją visiems, įsitikink, kad turi tinkamą ir reaguojančią prižiūrėjimo komandą! software_updates: - description: Rekomenduojama nuolat atnaujinti Mastodon diegyklę, kad galėtum naudotis naujausiais pataisymais ir funkcijomis. Be to, kartais labai svarbu laiku naujinti Mastodon, kad būtų išvengta saugumo problemų. Dėl šių priežasčių Mastodon kas 30 minučių tikrina, ar yra atnaujinimų, ir praneša tau apie tai pagal tavo el. pašto pranešimų parinktis. + description: Rekomenduojama nuolat atnaujinti Mastodon diegyklę, kad galėtum naudotis naujausiais pataisymais ir funkcijomis. Be to, kartais labai svarbu laiku atnaujinti Mastodon, kad būtų išvengta saugumo problemų. Dėl šių priežasčių Mastodon kas 30 minučių tikrina, ar yra naujinimų, ir praneša tau apie tai pagal tavo el. pašto pranešimų parinktis. + documentation_link: Sužinoti daugiau + release_notes: Leidimo informacija + title: Galimi naujinimai + type: Tipas + types: + major: Pagrindinis leidimas + minor: Nedidelis leidimas + patch: Pataiso leidimas – riktų taisymai ir lengvai pritaikomi pakeitimai + version: Versija statuses: + account: Autorius (-ė) + application: Programa back_to_account: Grįžti į paskyros puslapį + back_to_report: Grįžti į ataskaitos puslapį + batch: + remove_from_report: Pašalinti iš ataskaitos + deleted: Ištrinta + favourites: Mėgstami + history: Versijų istorija + in_reply_to: Atsakydant į + language: Kalba media: title: Medija - no_status_selected: Jokie statusai nebuvo pakeisti, nes niekas nepasirinkta + metadata: Metaduomenys + no_status_selected: Jokie įrašai nebuvo pakeisti, nes nė vienas buvo pasirinktas + open: Atidaryti įrašą + original_status: Originalus įrašas title: Paskyros statusai trending: Tendencinga with_media: Su medija @@ -537,6 +565,7 @@ lt: elasticsearch_preset: message_html: Tavo Elasticsearch klasteris turi daugiau nei vieną mazgą, bet Mastodon nėra sukonfigūruotas juos naudoti. elasticsearch_preset_single_node: + action: Žiūrėti dokumentaciją message_html: Tavo Elasticsearch klasteris turi tik vieną mazgą, ES_PRESET turėtų būti nustatyta į single_node_cluster. title: Administracija trends: @@ -571,8 +600,20 @@ lt: disallow_account: Neleisti autorių (-ę) no_status_selected: Jokie tendencingi įrašai nebuvo pakeisti, nes nė vienas iš jų nebuvo pasirinktas not_discoverable: Autorius (-ė) nesutiko, kad būtų galima juos atrasti + shared_by: + few: Bendrinta arba pamėgta %{friendly_count} kartus + many: Bendrinta arba pamėgta %{friendly_count} karto + one: Bendrinta arba pamėgta vieną kartą + other: Bendrinta arba pamėgta %{friendly_count} kartų title: Tendencingi įrašai tags: + dashboard: + tag_accounts_measure: unikalūs naudojimai + tag_languages_dimension: Populiariausios kalbos + tag_servers_dimension: Populiariausi serveriai + tag_servers_measure: skirtingi serveriai + tag_uses_measure: bendri naudojimai + listable: Gali būti siūloma not_trendable: Nepasirodys tendencijose title: Tendencingos saitažodžiai trendable: Gali pasirodyti tendencijose @@ -583,7 +624,6 @@ lt: add_new: Pridėti naują delete: Ištrinti edit_preset: Keisti įspėjimo nustatymus - title: Valdyti įspėjimo nustatymus webhooks: description_html: "Webhook leidžia Mastodon siųsti realaus laiko pranešimus apie pasirinktus įvykius į tavo programą, kad programa galėtų automatiškai paleisti reakcijas." events: Įvykiai @@ -627,21 +667,32 @@ lt: warning: Būkite atsargūs su šia informacija. Niekada jos nesidalinkite! your_token: Tavo prieigos raktas auth: + confirmations: + welcome_title: Sveiki, %{name}! delete_account: Ištrinti paskyrą delete_account_html: Jeigu norite ištrinti savo paskyrą, galite eiti čia. Jūsų prašys patvirtinti pasirinkimą. + description: + prefix_invited_by_user: "@%{name} kviečia prisijungti prie šio Mastodon serverio!" + prefix_sign_up: Užsiregistruok Mastodon šiandien! + didnt_get_confirmation: Negavai patvirtinimo nuorodos? dont_have_your_security_key: Neturi saugumo rakto? - forgot_password: Pamiršote slaptažodį? - invalid_reset_password_token: Slaptažodžio atkūrimo žetonas netinkamas arba jo galiojimo laikas pasibaigęs. Prašykite naujo žetono. + forgot_password: Pamiršai slaptažodį? + invalid_reset_password_token: Slaptažodžio atkūrimo raktas yra netinkamas arba nebegaliojantis. Paprašyk naujo. + log_in_with: Prisijungti su login: Prisijungti logout: Atsijungti migrate_account: Prisijungti prie kitos paskyros migrate_account_html: Jeigu norite nukreipti šią paskyrą į kita, galite tai konfiguruoti čia. or_log_in_with: Arba prisijungti su + providers: + cas: CAS + saml: SAML register: Užsiregistruoti reset_password: Atstatyti slaptažodį rules: invited_by: 'Gali prisijungti prie %{domain} pagal kvietimą, kurį gavai iš:' preamble_invited: Prieš tęsiant, atsižvelk į pagrindines taisykles, kurias nustatė %{domain} prižiūrėtojai. + title_invited: Esi pakviestas. security: Apsauga set_new_password: Nustatyti naują slaptažodį status: @@ -673,6 +724,9 @@ lt: success_msg: Tavo paskyra buvo sėkmingai ištrinta disputes: strikes: + created_at: Data + title_actions: + none: Įspėjimas your_appeal_approved: Tavo apeliacija buvo patvirtinta your_appeal_pending: Pateikei apeliaciją your_appeal_rejected: Tavo apeliacija buvo atmesta @@ -699,6 +753,8 @@ lt: request: Prašyti savo archyvo size: Dydis blocks: Jūs blokuojate + bookmarks: Žymės + csv: CSV domain_blocks: Domeno blokai lists: Sąrašai mutes: Jūs tildote @@ -708,11 +764,14 @@ lt: hint_html: "Savo profilyje parodyk svarbiausius saitažodžius. Tai puikus įrankis kūrybiniams darbams ir ilgalaikiams projektams sekti, todėl svarbiausios saitažodžiai rodomi matomoje vietoje profilyje ir leidžia greitai pasiekti tavo paties įrašus." filters: contexts: - home: Namų laiko juosta - notifications: Priminimai + account: Profiliai + home: Pagrindinis ir sąrašai + notifications: Pranešimai public: Viešieji laiko skalės thread: Pokalbiai edit: + add_keyword: Pridėti raktažodį + keywords: Raktažodžiai title: Keisti filtrą errors: invalid_context: Jokio arba netinkamas pateiktas kontekstas @@ -726,9 +785,14 @@ lt: all: Visi changes_saved_msg: Pakeitimai sėkmingai išsaugoti! copy: Kopijuoti + delete: Ištrinti + deselect: Panaikinti visus žymėjimus order_by: Tvarkyti pagal save_changes: Išsaugoti pakeitimus + today: šiandien imports: + errors: + too_large: Failas per didelis. modes: merge: Sulieti merge_long: Išsaugoti esančius įrašus ir pridėti naujus @@ -744,7 +808,7 @@ lt: upload: Įkelti invites: delete: Deaktyvuoti - expired: Pasibaigė + expired: Nebegaliojantis expires_in: '1800': 30 minučių '21600': 6 valandų @@ -753,28 +817,29 @@ lt: '604800': 1 savaitės '86400': 1 dienos expires_in_prompt: Niekada - generate: Generuoti + generate: Generuoti kvietimo nuorodą invalid: Šis kvietimas negalioja. - invited_by: 'Jus pakvietė:' + invited_by: 'Tave pakvietė:' max_uses: few: "%{count} naudojimai" many: "%{count} naudojimo" one: 1 naudojimas other: "%{count} naudojimų" - max_uses_prompt: Nėra limito + max_uses_prompt: Nėra ribojimo prompt: Generuok ir bendrink nuorodas su kitais, kad suteiktum prieigą prie šio serverio table: expires_at: Baigsis uses: Naudojimai - title: Pakviesti žmones + title: Kviesti žmones media_attachments: validations: images_and_video: Negalima pridėti video prie statuso, kuris jau turi nuotrauką too_many: Negalima pridėti daugiau nei 4 failų migrations: - acct: slapyvardis@domenas naujam vartotojui + acct: Perkelta į + cancel: Atšaukti nukreipimą moderation: - title: Moderacija + title: Prižiūrėjimas notification_mailer: favourite: body: 'Tavo įrašą pamėgo %{name}:' @@ -801,11 +866,19 @@ lt: notifications: email_events: Įvykiai, skirti el. laiško pranešimams email_events_hint: 'Pasirink įvykius, apie kuriuos nori gauti pranešimus:' + number: + human: + decimal_units: + units: + billion: mlrd. + million: mln. + thousand: tūkst. pagination: newer: Naujesnis next: Kitas older: Senesnis prev: Ankstesnis + truncate: "…" preferences: other: Kita posting_defaults: Skelbimo numatytosios nuostatos @@ -829,6 +902,7 @@ lt: dormant: Neaktyvus followers: Sekėjai following: Sekama + invited: Pakviestas last_active: Paskutinį kartą aktyvus most_recent: Naujausias moved: Perkelta @@ -851,24 +925,35 @@ lt: date: Data description: "%{browser} ant %{platform}" explanation: Čia rodomos web naršyklės prijungtos prie Jūsų Mastodon paskyros. + 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 + unknown_platform: Nežinoma platforma windows: Windows windows_mobile: Windows Mobile windows_phone: Windows Phone - revoke: Atšaukti + revoke: Naikinti revoke_success: Seansas sėkmingai panaikintas. title: Seansai settings: - authorized_apps: Autorizuotos aplikacijos + account: Paskyra + account_settings: Paskyros nustatymai + aliases: Paskyros pseudonimai + appearance: Išvaizda + authorized_apps: Leidžiamos programėlės back: Grįžti į Mastodon delete: Paskyros trynimas - development: Plėtojimas - edit_profile: Keisti profilį - export: Informacijos eksportas + development: Kūrimas + edit_profile: Redaguoti profilį + export: Duomenų eksportas featured_tags: Rodomi saitažodžiai import: Importuoti migrate: Paskyros migracija @@ -879,10 +964,22 @@ lt: severed_relationships: Nutrūkę sąryšiai two_factor_authentication: Dviejų veiksnių autentikacija severed_relationships: + download: Atsisiųsti (%{count}) preamble: Užblokavus domeną arba prižiūrėtojams nusprendus pristabdyti nuotolinio serverio veiklą, gali prarasti sekimus ir sekėjus. Kai taip atsitiks, galėsi atsisiųsti nutrauktų sąryšių sąrašus, kad juos patikrinti ir galbūt importuoti į kitą serverį. + type: Įvykis statuses: attached: + audio: + few: "%{count} garso įrašai" + many: "%{count} garso įrašo" + one: "%{count} garso įrašas" + other: "%{count} garso įrašų" description: 'Pridėta: %{attached}' + image: + few: "%{count} vaizdai" + many: "%{count} vaizdo" + one: "%{count} vaizdas" + other: "%{count} vaizdų" boosted_from_html: Pakelta iš %{acct_link} content_warning: 'Turinio įspėjimas: %{warning}' open_in_web: Atidaryti naudojan Web @@ -891,11 +988,14 @@ lt: limit: Jūs jau prisegėte maksimalų toot'ų skaičų ownership: Kitų vartotojų toot'ai negali būti prisegti reblog: Pakeltos žinutės negali būti prisegtos - show_more: Daugiau + poll: + vote: Balsuoti + show_more: Rodyti daugiau + show_thread: Rodyti giją visibilities: private: Tik sekėjams private_long: rodyti tik sekėjams - public: Viešas + public: Vieša public_long: visi gali matyti unlisted: Neįtrauktas į sąrašus unlisted_long: matyti gali visi, bet nėra išvardyti į viešąsias laiko skales @@ -904,6 +1004,7 @@ lt: keep_polls_hint: Neištrina jokių tavo apklausų keep_self_bookmark: Laikyti įrašus, kuriuos pažymėjai keep_self_bookmark_hint: Neištrina tavo pačių įrašų, jei esi juos pažymėjęs (-usi) + keep_self_fav_hint: Neištrina tavo pačių įrašų, jei esi juos pamėgęs (-usi) stream_entries: sensitive_content: Jautrus turinys themes: @@ -912,7 +1013,8 @@ lt: mastodon-light: Mastodon (šviesi) system: Automatinis (naudoti sistemos temą) two_factor_authentication: - disable: Išjungti + add: Pridėti + disable: Išjungti 2FA enabled: Dviejų veiksnių autentikacija įjungta enabled_success: Dviejų veiksnių autentikacija sėkmingai įjungta generate_recovery_codes: Sugeneruoti atkūrimo kodus diff --git a/config/locales/lv.yml b/config/locales/lv.yml index f4f0aa9db2..5a071eba86 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -961,7 +961,6 @@ lv: delete: Dzēst edit_preset: Labot iepriekš iestatītus brīdinājumus empty: Tu vēl neesi definējis iepriekš iestatītos brīdinājumus. - title: Pārvaldīt brīdinājuma iestatījumus webhooks: add_new: Pievienot galapunktu delete: Dzēst diff --git a/config/locales/ms.yml b/config/locales/ms.yml index f39c26a5c1..a778d0c28f 100644 --- a/config/locales/ms.yml +++ b/config/locales/ms.yml @@ -924,7 +924,6 @@ ms: delete: Padam edit_preset: Edit pratetap amaran empty: Anda belum menentukan sebarang pratetap amaran lagi. - title: Urus pratetap amaran webhooks: add_new: Tambah titik akhir delete: Padam diff --git a/config/locales/my.yml b/config/locales/my.yml index 4ac9ecdd45..f28458360b 100644 --- a/config/locales/my.yml +++ b/config/locales/my.yml @@ -909,7 +909,6 @@ my: delete: ဖျက်ပါ edit_preset: ကြိုသတိပေးချက်ကို ပြင်ဆင်ပါ empty: ကြိုသတိပေးချက်များကို မသတ်မှတ်ရသေးပါ။ - title: ကြိုသတိပေးချက်များကို စီမံပါ webhooks: add_new: ဆုံးမှတ် ထည့်ပါ delete: ဖျက်ပါ diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 3452f80994..a527fdb5a7 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -951,7 +951,7 @@ nl: delete: Verwijderen edit_preset: Preset voor waarschuwing bewerken empty: Je hebt nog geen presets voor waarschuwingen toegevoegd. - title: Presets voor waarschuwingen beheren + title: Presets voor waarschuwingen webhooks: add_new: Eindpunt toevoegen delete: Verwijderen diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 013674ca51..9291ba2c2c 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -950,7 +950,6 @@ nn: delete: Slett edit_preset: Endr åtvaringsoppsett empty: Du har ikke definert noen forhåndsinnstillinger for advarsler enda. - title: Handsam åtvaringsoppsett webhooks: add_new: Legg til endepunkt delete: Slett diff --git a/config/locales/no.yml b/config/locales/no.yml index c71dffc636..537552ea98 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -944,7 +944,6 @@ delete: Slett edit_preset: Rediger advarsel forhåndsinnstilling empty: Du har ikke definert noen forhåndsinnstillinger for varsler enda. - title: Endre forhåndsinnstillinger for advarsler webhooks: add_new: Legg til endepunkt delete: Slett diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 0a653ea46c..d2bea55bd3 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -430,7 +430,6 @@ oc: add_new: N’ajustar un nòu delete: Escafar edit_preset: Modificar lo tèxt predefinit d’avertiment - title: Gerir los tèxtes predefinits webhooks: delete: Suprimir disable: Desactivar diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 1c3fda8d03..4c7af82b94 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -985,7 +985,7 @@ pl: delete: Usuń edit_preset: Edytuj szablon ostrzeżenia empty: Nie zdefiniowano jeszcze żadnych szablonów ostrzegawczych. - title: Zarządzaj szablonami ostrzeżeń + title: Zapisane ostrzeżenia webhooks: add_new: Dodaj punkt końcowy delete: Usuń diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 60730d53e9..6b80edb24e 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -950,7 +950,6 @@ pt-BR: delete: Excluir edit_preset: Editar o aviso pré-definido empty: Você ainda não definiu nenhuma predefinição de alerta. - title: Gerenciar os avisos pré-definidos webhooks: add_new: Adicionar endpoint delete: Excluir diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index b4669e24d8..49522b7414 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -951,7 +951,7 @@ pt-PT: delete: Eliminar edit_preset: Editar o aviso predefinido empty: Ainda não definiu nenhum aviso predefinido. - title: Gerir os avisos predefinidos + title: Predefinições de aviso webhooks: add_new: Adicionar endpoint delete: Eliminar diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 85d8a7a540..d6b8726ba4 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -978,7 +978,6 @@ ru: delete: Удалить edit_preset: Удалить шаблон предупреждения empty: Вы еще не определили пресеты предупреждений. - title: Управление шаблонами предупреждений webhooks: add_new: Добавить конечную точку delete: Удалить diff --git a/config/locales/sc.yml b/config/locales/sc.yml index 01c355794d..449d8d9c7f 100644 --- a/config/locales/sc.yml +++ b/config/locales/sc.yml @@ -535,7 +535,6 @@ sc: delete: Cantzella edit_preset: Modìfica s'avisu predefinidu empty: No as cunfiguradu ancora perunu avisu predefinidu. - title: Gesti is cunfiguratziones predefinidas de is avisos webhooks: delete: Cantzella disable: Disativa diff --git a/config/locales/sco.yml b/config/locales/sco.yml index 2a7b1e3e70..7c733b71b5 100644 --- a/config/locales/sco.yml +++ b/config/locales/sco.yml @@ -842,7 +842,6 @@ sco: delete: Delete edit_preset: Edit warnin preset empty: Ye huvnae definit onie warnin presets yit. - title: Manage warnin presets webhooks: add_new: Add enpynt delete: Delete diff --git a/config/locales/si.yml b/config/locales/si.yml index f5e65fda8d..0f714ee146 100644 --- a/config/locales/si.yml +++ b/config/locales/si.yml @@ -726,7 +726,6 @@ si: delete: මකන්න edit_preset: අනතුරු ඇඟවීමේ පෙර සැකසුම සංස්කරණය කරන්න empty: ඔබ තවම කිසිදු අනතුරු ඇඟවීමේ පෙරසිටුවක් නිර්වචනය කර නැත. - title: අනතුරු ඇඟවීමේ පෙරසිටුවීම් කළමනාකරණය කරන්න webhooks: add_new: අන්ත ලක්ෂ්‍යය එක් කරන්න delete: මකන්න diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index 1c73ce0a84..789121be42 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -79,6 +79,7 @@ lt: mascot: Pakeičia išplėstinės žiniatinklio sąsajos iliustraciją. media_cache_retention_period: Nuotolinių naudotojų įrašytų įrašų medijos failai talpinami tavo serveryje. Nustačius teigiamą reikšmę, medijos bus ištrinamos po nurodyto dienų skaičiaus. Jei medijos duomenų bus paprašyta po to, kai jie bus ištrinti, jie bus atsiųsti iš naujo, jei šaltinio turinys vis dar prieinamas. Dėl apribojimų, susijusių su nuorodų peržiūros kortelių apklausos dažnumu trečiųjų šalių svetainėse, rekomenduojama nustatyti šią reikšmę ne trumpesnę kaip 14 dienų, kitaip nuorodų peržiūros kortelės nebus atnaujinamos pagal pareikalavimą iki to laiko. peers_api_enabled: Domenų pavadinimų sąrašas, su kuriais šis serveris susidūrė fediverse. Čia nėra duomenų apie tai, ar tu bendrauji su tam tikru serveriu, tik apie tai, kad tavo serveris apie jį žino. Tai naudojama tarnybose, kurios renka federacijos statistiką bendrąja prasme. + require_invite_text: Kai registraciją reikia patvirtinti rankiniu būdu, teksto įvesties laukelį „Kodėl nori prisijungti?“ padaryk privalomą, o ne pasirenkamą site_contact_email: Kaip žmonės gali su tavimi susisiekti teisiniais ar pagalbos užklausimais. site_contact_username: Kaip žmonės gali tave pasiekti Mastodon. site_extended_description: Bet kokia papildoma informacija, kuri gali būti naudinga lankytojams ir naudotojams. Gali būti struktūrizuota naudojant Markdown sintaksę. @@ -86,6 +87,8 @@ lt: timeline_preview: Atsijungę lankytojai galės naršyti naujausius viešus įrašus, esančius serveryje. trends: Trendai rodo, kurios įrašai, saitažodžiai ir naujienų istorijos tavo serveryje sulaukia didžiausio susidomėjimo. trends_as_landing_page: Rodyti tendencingą turinį atsijungusiems naudotojams ir lankytojams vietoj šio serverio aprašymo. Reikia, kad tendencijos būtų įjungtos. + invite_request: + text: Tai padės mums peržiūrėti tavo paraišką rule: hint: Pasirinktinai. Pateik daugiau informacijos apie taisyklę. sessions: @@ -108,6 +111,7 @@ lt: admin_account_action: include_statuses: Įtraukti praneštus įrašus į el. laišką defaults: + autofollow: Kviesti sekti tavo paskyrą avatar: Profilio nuotrauka bot: Tai automatinė paskyra chosen_languages: Filtruoti kalbas @@ -163,6 +167,7 @@ lt: custom_css: Pasirinktinis CSS mascot: Pasirinktinis talismanas (pasenęs) registrations_mode: Kas gali užsiregistruoti + require_invite_text: Reikalauti priežasties prisijungti show_domain_blocks_rationale: Rodyti, kodėl domenai buvo užblokuoti site_extended_description: Išplėstas aprašymas site_short_description: Serverio aprašymas @@ -173,6 +178,8 @@ lt: trendable_by_default: Leisti tendencijas be išankstinės peržiūros trends: Įjungti tendencijas trends_as_landing_page: Naudoti tendencijas kaip nukreipimo puslapį + invite: + comment: Komentuoti invite_request: text: Kodėl nori prisijungti? notification_emails: diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml index 8bc717fe1f..2271d7037e 100644 --- a/config/locales/simple_form.nl.yml +++ b/config/locales/simple_form.nl.yml @@ -28,7 +28,7 @@ nl: sensitive: Forceer dat alle mediabijlagen van deze gebruiker als gevoelig worden gemarkeerd. silence: Voorkom dat de gebruiker berichten kan plaatsen met openbare zichtbaarheid, verberg diens berichten en meldingen van mensen die de gebruiker niet volgen. Sluit alle rapportages tegen dit account af. suspend: Voorkom interactie van of naar dit account en verwijder de inhoud. Dit is omkeerbaar binnen 30 dagen. Dit sluit alle rapporten tegen dit account af. - warning_preset_id: Optioneel. Je kunt nog steeds handmatig tekst toevoegen aan het eind van de voorinstelling + warning_preset_id: Optioneel. Je kunt nog steeds handmatig tekst toevoegen aan het eind van de preset announcement: all_day: Wanneer dit is aangevinkt worden alleen de datums binnen het tijdvak getoond ends_at: Optioneel. De publicatie van de mededeling wordt op dit tijdstip automatisch beëindigd @@ -168,7 +168,7 @@ nl: sensitive: Gevoelig silence: Beperken suspend: Opschorten en onomkeerbaar accountgegevens verwijderen - warning_preset_id: Gebruik een voorinstelling van een waarschuwing + warning_preset_id: Een preset voor een waarschuwing gebruiken announcement: all_day: Gedurende de hele dag ends_at: Eindigt diff --git a/config/locales/simple_form.sr-Latn.yml b/config/locales/simple_form.sr-Latn.yml index 8dd1986563..710f81e84f 100644 --- a/config/locales/simple_form.sr-Latn.yml +++ b/config/locales/simple_form.sr-Latn.yml @@ -20,7 +20,7 @@ sr-Latn: admin_account_action: include_statuses: Korisnik će videti koje su objave prouzrokovale moderacijsku radnju ili upozorenje send_email_notification: Korisnik će dobiti objašnjenje toga šta mu se desilo sa nalogom - text_html: Opcionalno. Možete koristiti sintaksu objava. Možete dodati unapred određene postavke upozorenja za uštedu vremena + text_html: Opciono. Možete koristiti sintaksu objava. Možete dodati predefinisana upozorenja za uštedu vremena type_html: Izaberite šta da radite sa %{acct} types: disable: Sprečava korisnika da koristi svoj nalog, ali ne briše niti sakriva njegove sadržaje. @@ -28,7 +28,7 @@ sr-Latn: sensitive: Učini da svi medijski prilozi ovog korisnika prisilno budu označeni kao osetljivi. silence: Sprečava korisnika da pravi javne objave, sakriva njegove objave i obaveštenja od ljudi koji ga ne prate. Zatvara sve prijave podnete protiv ovog naloga. suspend: Sprečava svu interakciju od ovog naloga i ka ovom nalogu i briše njegov sadržaj. Opozivo u roku od 30 dana. Zatvara sve prijave podnete protiv ovog naloga. - warning_preset_id: Opcionalno. Možete i dalje dodati prilagođeni tekst na kraj preseta + warning_preset_id: Opciono. Možete i dalje dodati prilagođeni tekst na kraj predefinisane vrednosti announcement: all_day: Kada je ova opcija označena, samo datumi iz vremenskog opsega će biti prikazani ends_at: Opciono. Objava će biti automatski opozvana u ovom trenutku @@ -118,7 +118,7 @@ sr-Latn: sign_up_requires_approval: Nove registracije će zahtevati Vaše odobrenje severity: Izaberite šta će se desiti sa zahtevima sa ove IP adrese rule: - hint: Opcionalno. Pružite više detalja o pravilu + hint: Opciono. Pružite više detalja o pravilu text: Opišite pravilo ili uslov za korisnike na ovom serveru. Potrudite se da opis bude kratak i jednostavan sessions: otp: 'Unesite dvofaktorski kod sa Vašeg telefona ili koristite jedan od kodova za oporavak:' @@ -155,7 +155,7 @@ sr-Latn: account_migration: acct: Ručica (@) novog naloga account_warning_preset: - text: Tekst preseta + text: Tekst predefinisane vrednosti title: Naslov admin_account_action: include_statuses: Uključi prijavljene objave u e-poštu @@ -168,7 +168,7 @@ sr-Latn: sensitive: Osetljivo silence: Utišaj suspend: Obustavite i nepovratno izbrišite podatke o nalogu - warning_preset_id: Koristi upozoravajući preset + warning_preset_id: Koristi predefinisano upozorenje announcement: all_day: Celodnevni događaj ends_at: Kraj događaja diff --git a/config/locales/simple_form.sr.yml b/config/locales/simple_form.sr.yml index e88a99df13..c5fbc9185a 100644 --- a/config/locales/simple_form.sr.yml +++ b/config/locales/simple_form.sr.yml @@ -20,7 +20,7 @@ sr: admin_account_action: include_statuses: Корисник ће видети које су објаве проузроковале модерацијску радњу или упозорење send_email_notification: Корисник ће добити објашњење тога шта му се десило са налогом - text_html: Опционално. Можете користити синтаксу објава. Можете додати унапред одређене поставке упозорења за уштеду времена + text_html: Опционо. Можете користити синтаксу објава. Можете додати предефинисана упозорења за уштеду времена type_html: Изаберите шта да радите са %{acct} types: disable: Спречава корисника да користи свој налог, али не брише нити сакрива његове садржаје. @@ -28,7 +28,7 @@ sr: sensitive: Учини да сви медијски прилози овог корисника присилно буду означени као осетљиви. silence: Спречава корисника да прави јавне објаве, сакрива његове објаве и обавештења од људи који га не прате. Затвара све пријаве поднете против овог налога. suspend: Спречава сву интеракцију од овог налога и ка овом налогу и брише његов садржај. Опозиво у року од 30 дана. Затвара све пријаве поднете против овог налога. - warning_preset_id: Опционално. Можете и даље додати прилагођени текст на крај пресета + warning_preset_id: Опционо. Можете и даље додати прилагођени текст на крај предефинисане вредности announcement: all_day: Када је ова опција означена, само датуми из временског опсега ће бити приказани ends_at: Опционо. Објава ће бити аутоматски опозвана у овом тренутку @@ -88,7 +88,7 @@ sr: media_cache_retention_period: Медијске датотеке из објава удаљених корисника се кеширају на вашем серверу. Када се подеси на позитивну вредност, медији ће бити избрисани након наведеног броја дана. Ако се медијски подаци захтевају након брисања, биће поново преузети, ако је изворни садржај и даље доступан. Због ограничења колико често картице за преглед веза анкетирају сајтове трећих страна, препоручује се да ову вредност поставите на најмање 14 дана, иначе картице за преглед веза неће бити ажуриране на захтев пре тог времена. peers_api_enabled: Листа домена са којима се овај сервер сусрео у федиверзуму. Овде нису садржани подаци о томе да ли се Ваш сервер федерише са другим серверима, већ само да Ваш сервер зна за њих. Ове информације користе сервиси који прикупљају податке и воде статистику о федерацији у ширем смислу. profile_directory: Директоријум профила наводи све кориснике који су се определили да буду видљиви. - require_invite_text: Када регистрације захтевају ручно одобрење, поставите да одговор на „Зашто желите да се придружите?“ буде обавезан, а не опционалан + require_invite_text: Када регистрације захтевају ручно одобрење, постави да унос текста „Зашто желиш да се придружиш?“ буде обавезан, а не опциони site_contact_email: Како корисници могу да контактирају са Вама за правна питања или питања у вези подршке. site_contact_username: Како корисници могу да контактирају са вама на Mastodon-у. site_extended_description: Било какве додатне информације које могу бити корисне посетиоцима и Вашим корисницима. Могу се структурирати помоћу Markdown синтаксе. @@ -118,7 +118,7 @@ sr: sign_up_requires_approval: Нове регистрације ће захтевати Ваше одобрење severity: Изаберите шта ће се десити са захтевима са ове IP адресе rule: - hint: Опционално. Пружите више детаља о правилу + hint: Опционо. Пружите више детаља о правилу text: Опишите правило или услов за кориснике на овом серверу. Потрудите се да опис буде кратак и једноставан sessions: otp: 'Унесите двофакторски код са Вашег телефона или користите један од кодова за опоравак:' @@ -155,7 +155,7 @@ sr: account_migration: acct: Ручица (@) новог налога account_warning_preset: - text: Текст пресета + text: Текст предефинисане вредности title: Наслов admin_account_action: include_statuses: Укључи пријављене објаве у е-пошту @@ -168,7 +168,7 @@ sr: sensitive: Осетљиво silence: Утишај suspend: Обуставите и неповратно избришите податке о налогу - warning_preset_id: Користи упозоравајући пресет + warning_preset_id: Користи предефинисано упозорење announcement: all_day: Целодневни догађај ends_at: Крај догађаја diff --git a/config/locales/sk.yml b/config/locales/sk.yml index f05887dc33..f10815129d 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -763,7 +763,6 @@ sk: add_new: Pridaj nové delete: Vymaž edit_preset: Uprav varovnú predlohu - title: Spravuj varovné predlohy webhooks: delete: Vymaž disable: Vypni diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 329ce5a29b..1e4e254cf1 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -985,7 +985,7 @@ sl: delete: Izbriši edit_preset: Uredi prednastavitev opozoril empty: Zaenkrat še niste določili nobenih opozorilnih prednastavitev. - title: Upravljaj prednastavitev opozoril + title: Pred-nastavitve opozoril webhooks: add_new: Dodaj končno točko delete: Izbriši diff --git a/config/locales/sq.yml b/config/locales/sq.yml index 8319cfcaec..5439f08a04 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -285,6 +285,7 @@ sq: update_custom_emoji_html: "%{name} përditësoi emoxhin %{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_report_html: "%{name} përditësoi raportimin %{target}" update_status_html: "%{name} përditësoi gjendjen me %{target}" update_user_role_html: "%{name} ndryshoi rolin për %{target}" deleted_account: fshiu llogarinë @@ -946,7 +947,7 @@ sq: delete: Fshije edit_preset: Përpunoni sinjalizim të paracaktuar empty: S’keni përcaktuar ende sinjalizime të gatshme. - title: Administroni sinjalizime të paracaktuara + title: Paracaktime sinjalizimesh webhooks: add_new: Shtoni pikëmbarim delete: Fshije diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 808a10e729..718d1c0f84 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -869,7 +869,7 @@ sr-Latn: action: Pogledaj dokumentaciju message_html: Vaš Elasticsearch klaster ima samo jedan čvor, ES_PRESETtreba postaviti nasingle_node_cluster. elasticsearch_reset_chewy: - message_html: Vaš Elasticsearch klaster ima samo jedan čvor, ES_PRESETtreba postaviti nasingle_node_cluster. + message_html: Indeks Elasticsearch sistema je zastareo zbog promene podešavanja. Pokrenite tootctl search deploy --reset-chewyda biste ga ažurirali. elasticsearch_running_check: message_html: Povezivanje na Elasticsearch nije bilo moguće. Molimo Vas proverite da li je pokrenut, ili onemogućite pretragu celog teksta elasticsearch_version_check: @@ -966,9 +966,9 @@ sr-Latn: warning_presets: add_new: Dodaj novi delete: Izbriši - edit_preset: Uredi preset upozorenja - empty: Još uvek niste definisali nijedan šablon upozorenja. - title: Upravljaj presetima upozorenja + edit_preset: Uredi predefinisana upozorenja + empty: Još uvek niste definisali nijedno upozorenje. + title: Predefinisana upozorenja webhooks: add_new: Dodaj krajnju tačku delete: Izbriši diff --git a/config/locales/sr.yml b/config/locales/sr.yml index f03c6e878a..c9a67b1936 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -869,7 +869,7 @@ sr: action: Погледај документацију message_html: Ваш Elasticsearch кластер има само један чвор, ES_PRESETтреба поставити наsingle_node_cluster. elasticsearch_reset_chewy: - message_html: Ваш Elasticsearch кластер има само један чвор, ES_PRESETтреба поставити наsingle_node_cluster. + message_html: Индекс Elasticsearch система је застарео због промене подешавања. Покрените tootctl search deploy --reset-chewyда бисте га ажурирали. elasticsearch_running_check: message_html: Повезивање на Elasticsearch није било могуће. Молимо Вас проверите да ли је покренут, или онемогућите претрагу целог текста elasticsearch_version_check: @@ -966,9 +966,9 @@ sr: warning_presets: add_new: Додај нови delete: Избриши - edit_preset: Уреди пресет упозорења - empty: Још увек нисте дефинисали ниједан шаблон упозорења. - title: Управљај пресетима упозорења + edit_preset: Уреди предефинисана упозорења + empty: Још увек нисте дефинисали ниједно упозорење. + title: Предефинисна упозорења webhooks: add_new: Додај крајњу тачку delete: Избриши diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 9f0de4a723..cf68cdd563 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -951,7 +951,6 @@ sv: delete: Radera edit_preset: Redigera varningsförval empty: Du har inte definierat några varningsförval ännu. - title: Hantera varningsförval webhooks: add_new: Lägg till slutpunkt delete: Ta bort diff --git a/config/locales/th.yml b/config/locales/th.yml index 5711f68ff8..3ca4f09733 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -934,7 +934,6 @@ th: delete: ลบ edit_preset: แก้ไขคำเตือนที่ตั้งไว้ล่วงหน้า empty: คุณยังไม่ได้กำหนดคำเตือนที่ตั้งไว้ล่วงหน้าใด ๆ - title: จัดการคำเตือนที่ตั้งไว้ล่วงหน้า webhooks: add_new: เพิ่มปลายทาง delete: ลบ diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 469f2c5ad8..3ce12fec87 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -951,7 +951,7 @@ tr: delete: Sil edit_preset: Uyarı ön-ayarını düzenle empty: Henüz önceden ayarlanmış bir uyarı tanımlanmadı. - title: Uyarı ön-ayarlarını yönet + title: Uyarı Önayarları webhooks: add_new: Uç nokta ekle delete: Sil diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 71e84a1d54..5baaa93870 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -984,7 +984,6 @@ uk: delete: Видалити edit_preset: Редагувати шаблон попередження empty: Ви ще не визначили жодних попереджень. - title: Керування шаблонами попереджень webhooks: add_new: Додати кінцеву точку delete: Видалити diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 05f3157ec9..4265c1a33a 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -934,7 +934,6 @@ vi: delete: Xóa bỏ edit_preset: Sửa mẫu có sẵn empty: Bạn chưa thêm mẫu cảnh cáo nào cả. - title: Quản lý mẫu cảnh cáo webhooks: add_new: Thêm endpoint delete: Xóa bỏ diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 12b6197938..b668c23d29 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -934,7 +934,7 @@ zh-CN: delete: 删除 edit_preset: 编辑预置警告 empty: 你尚未定义任何警告预设。 - title: 管理预设警告 + title: 预设警告 webhooks: add_new: 新增对端 delete: 删除 diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index 1bfbe38bb5..ddc6571e6d 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -933,7 +933,6 @@ zh-HK: delete: 刪除 edit_preset: 設定警告預設 empty: 您尚未定義任何預設警告 - title: 管理警告預設 webhooks: add_new: 新增端點 delete: 刪除 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index ac633a201d..14f54f9a12 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -936,7 +936,7 @@ zh-TW: delete: 刪除 edit_preset: 編輯預設警告 empty: 您尚未定義任何預設警告。 - title: 管理預設警告 + title: 預設警告內容 webhooks: add_new: 新增端點 delete: 刪除 From 3a862439dfc989c6c5741e007c2f4e0335fffe33 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 23 May 2024 04:26:58 -0400 Subject: [PATCH 226/658] Remove unused account record in api/v2/admin/accounts spec (#30397) --- spec/requests/api/v2/admin/accounts_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/requests/api/v2/admin/accounts_spec.rb b/spec/requests/api/v2/admin/accounts_spec.rb index fb04850bb7..f5db93233c 100644 --- a/spec/requests/api/v2/admin/accounts_spec.rb +++ b/spec/requests/api/v2/admin/accounts_spec.rb @@ -8,7 +8,6 @@ RSpec.describe 'API V2 Admin Accounts' do let(:scopes) { 'admin:read admin:write' } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - let(:account) { Fabricate(:account) } describe 'GET #index' do let!(:remote_account) { Fabricate(:account, domain: 'example.org') } From 10ec421dd4e0da987e69a3dd7f4f696f9c5878e0 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 23 May 2024 11:50:13 +0200 Subject: [PATCH 227/658] Proposal: a modern & typed way of writing Redux actions doing API requests (#30270) --- .../mastodon/actions/account_notes.ts | 21 +- .../mastodon/actions/interactions.js | 86 +------- .../mastodon/actions/interactions_typed.ts | 30 +++ app/javascript/mastodon/api.ts | 16 +- app/javascript/mastodon/api/accounts.ts | 7 + app/javascript/mastodon/api/interactions.ts | 10 + .../mastodon/containers/status_container.jsx | 4 +- .../containers/account_note_container.js | 2 +- .../containers/notification_container.js | 4 +- .../picture_in_picture/components/footer.jsx | 4 +- .../containers/detailed_status_container.js | 4 +- .../mastodon/features/status/index.jsx | 4 +- app/javascript/mastodon/reducers/statuses.js | 28 +-- .../mastodon/store/typed_functions.ts | 186 ++++++++++++++++++ 14 files changed, 281 insertions(+), 125 deletions(-) create mode 100644 app/javascript/mastodon/actions/interactions_typed.ts create mode 100644 app/javascript/mastodon/api/accounts.ts create mode 100644 app/javascript/mastodon/api/interactions.ts diff --git a/app/javascript/mastodon/actions/account_notes.ts b/app/javascript/mastodon/actions/account_notes.ts index acd9ecf410..bf4f93dca9 100644 --- a/app/javascript/mastodon/actions/account_notes.ts +++ b/app/javascript/mastodon/actions/account_notes.ts @@ -1,18 +1,9 @@ -import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships'; -import { createAppAsyncThunk } from 'mastodon/store/typed_functions'; +import { apiSubmitAccountNote } from 'mastodon/api/accounts'; +import { createDataLoadingThunk } from 'mastodon/store/typed_functions'; -import api from '../api'; - -export const submitAccountNote = createAppAsyncThunk( +export const submitAccountNote = createDataLoadingThunk( 'account_note/submit', - async (args: { id: string; value: string }) => { - const response = await api().post( - `/api/v1/accounts/${args.id}/note`, - { - comment: args.value, - }, - ); - - return { relationship: response.data }; - }, + (accountId: string, note: string) => apiSubmitAccountNote(accountId, note), + (relationship) => ({ relationship }), + { skipLoading: true }, ); diff --git a/app/javascript/mastodon/actions/interactions.js b/app/javascript/mastodon/actions/interactions.js index fe7c911b61..57f2459c01 100644 --- a/app/javascript/mastodon/actions/interactions.js +++ b/app/javascript/mastodon/actions/interactions.js @@ -3,10 +3,6 @@ import api, { getLinks } from '../api'; import { fetchRelationships } from './accounts'; import { importFetchedAccounts, importFetchedStatus } from './importer'; -export const REBLOG_REQUEST = 'REBLOG_REQUEST'; -export const REBLOG_SUCCESS = 'REBLOG_SUCCESS'; -export const REBLOG_FAIL = 'REBLOG_FAIL'; - export const REBLOGS_EXPAND_REQUEST = 'REBLOGS_EXPAND_REQUEST'; export const REBLOGS_EXPAND_SUCCESS = 'REBLOGS_EXPAND_SUCCESS'; export const REBLOGS_EXPAND_FAIL = 'REBLOGS_EXPAND_FAIL'; @@ -15,10 +11,6 @@ export const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST'; export const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS'; export const FAVOURITE_FAIL = 'FAVOURITE_FAIL'; -export const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST'; -export const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS'; -export const UNREBLOG_FAIL = 'UNREBLOG_FAIL'; - export const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST'; export const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS'; export const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL'; @@ -51,83 +43,7 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST'; export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS'; export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL'; -export function reblog(status, visibility) { - return function (dispatch) { - dispatch(reblogRequest(status)); - - api().post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) { - // The reblog API method returns a new status wrapped around the original. In this case we are only - // interested in how the original is modified, hence passing it skipping the wrapper - dispatch(importFetchedStatus(response.data.reblog)); - dispatch(reblogSuccess(status)); - }).catch(function (error) { - dispatch(reblogFail(status, error)); - }); - }; -} - -export function unreblog(status) { - return (dispatch) => { - dispatch(unreblogRequest(status)); - - api().post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { - dispatch(importFetchedStatus(response.data)); - dispatch(unreblogSuccess(status)); - }).catch(error => { - dispatch(unreblogFail(status, error)); - }); - }; -} - -export function reblogRequest(status) { - return { - type: REBLOG_REQUEST, - status: status, - skipLoading: true, - }; -} - -export function reblogSuccess(status) { - return { - type: REBLOG_SUCCESS, - status: status, - skipLoading: true, - }; -} - -export function reblogFail(status, error) { - return { - type: REBLOG_FAIL, - status: status, - error: error, - skipLoading: true, - }; -} - -export function unreblogRequest(status) { - return { - type: UNREBLOG_REQUEST, - status: status, - skipLoading: true, - }; -} - -export function unreblogSuccess(status) { - return { - type: UNREBLOG_SUCCESS, - status: status, - skipLoading: true, - }; -} - -export function unreblogFail(status, error) { - return { - type: UNREBLOG_FAIL, - status: status, - error: error, - skipLoading: true, - }; -} +export * from "./interactions_typed"; export function favourite(status) { return function (dispatch) { diff --git a/app/javascript/mastodon/actions/interactions_typed.ts b/app/javascript/mastodon/actions/interactions_typed.ts new file mode 100644 index 0000000000..5180806087 --- /dev/null +++ b/app/javascript/mastodon/actions/interactions_typed.ts @@ -0,0 +1,30 @@ +import { apiReblog, apiUnreblog } from 'mastodon/api/interactions'; +import type { StatusVisibility } from 'mastodon/models/status'; +import { createDataLoadingThunk } from 'mastodon/store/typed_functions'; + +import { importFetchedStatus } from './importer'; + +export const reblog = createDataLoadingThunk( + 'status/reblog', + (statusId: string, visibility: StatusVisibility) => + apiReblog(statusId, visibility), + (data, { dispatch, discardLoadData }) => { + // The reblog API method returns a new status wrapped around the original. In this case we are only + // interested in how the original is modified, hence passing it skipping the wrapper + dispatch(importFetchedStatus(data.reblog)); + + // The payload is not used in any actions + return discardLoadData; + }, +); + +export const unreblog = createDataLoadingThunk( + 'status/unreblog', + (statusId: string) => apiUnreblog(statusId), + (data, { dispatch, discardLoadData }) => { + dispatch(importFetchedStatus(data)); + + // The payload is not used in any actions + return discardLoadData; + }, +); diff --git a/app/javascript/mastodon/api.ts b/app/javascript/mastodon/api.ts index 2ccf178f00..4e5ccef08c 100644 --- a/app/javascript/mastodon/api.ts +++ b/app/javascript/mastodon/api.ts @@ -1,4 +1,4 @@ -import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios'; +import type { AxiosResponse, Method, RawAxiosRequestHeaders } from 'axios'; import axios from 'axios'; import LinkHeader from 'http-link-header'; @@ -58,3 +58,17 @@ export default function api(withAuthorization = true) { ], }); } + +export async function apiRequest( + method: Method, + url: string, + params?: unknown, +) { + const { data } = await api().request({ + method, + url, + params, + }); + + return data; +} diff --git a/app/javascript/mastodon/api/accounts.ts b/app/javascript/mastodon/api/accounts.ts new file mode 100644 index 0000000000..51b1f4f8de --- /dev/null +++ b/app/javascript/mastodon/api/accounts.ts @@ -0,0 +1,7 @@ +import { apiRequest } from 'mastodon/api'; +import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships'; + +export const apiSubmitAccountNote = (id: string, value: string) => + apiRequest('post', `/api/v1/accounts/${id}/note`, { + comment: value, + }); diff --git a/app/javascript/mastodon/api/interactions.ts b/app/javascript/mastodon/api/interactions.ts new file mode 100644 index 0000000000..4c466a1b46 --- /dev/null +++ b/app/javascript/mastodon/api/interactions.ts @@ -0,0 +1,10 @@ +import { apiRequest } from 'mastodon/api'; +import type { Status, StatusVisibility } from 'mastodon/models/status'; + +export const apiReblog = (statusId: string, visibility: StatusVisibility) => + apiRequest<{ reblog: Status }>('post', `v1/statuses/${statusId}/reblog`, { + visibility, + }); + +export const apiUnreblog = (statusId: string) => + apiRequest('post', `v1/statuses/${statusId}/unreblog`); diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx index c6842e8df8..0174e5a02c 100644 --- a/app/javascript/mastodon/containers/status_container.jsx +++ b/app/javascript/mastodon/containers/status_container.jsx @@ -96,9 +96,9 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ onModalReblog (status, privacy) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else { - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); } }, diff --git a/app/javascript/mastodon/features/account/containers/account_note_container.js b/app/javascript/mastodon/features/account/containers/account_note_container.js index 20304a4524..9fbe0671c0 100644 --- a/app/javascript/mastodon/features/account/containers/account_note_container.js +++ b/app/javascript/mastodon/features/account/containers/account_note_container.js @@ -11,7 +11,7 @@ const mapStateToProps = (state, { account }) => ({ const mapDispatchToProps = (dispatch, { account }) => ({ onSave (value) { - dispatch(submitAccountNote({ id: account.get('id'), value})); + dispatch(submitAccountNote(account.get('id'), value)); }, }); diff --git a/app/javascript/mastodon/features/notifications/containers/notification_container.js b/app/javascript/mastodon/features/notifications/containers/notification_container.js index de450cd1ab..d829cb833e 100644 --- a/app/javascript/mastodon/features/notifications/containers/notification_container.js +++ b/app/javascript/mastodon/features/notifications/containers/notification_container.js @@ -39,12 +39,12 @@ const mapDispatchToProps = dispatch => ({ }, onModalReblog (status, privacy) { - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else { if (e.shiftKey || !boostModal) { this.onModalReblog(status); diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx index d6b1b5fa81..1c142f3c10 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx @@ -123,7 +123,7 @@ class Footer extends ImmutablePureComponent { _performReblog = (status, privacy) => { const { dispatch } = this.props; - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); }; handleReblogClick = e => { @@ -132,7 +132,7 @@ class Footer extends ImmutablePureComponent { if (signedIn) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else if ((e && e.shiftKey) || !boostModal) { this._performReblog(status); } else { diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js index 1c650f544f..91bc700e98 100644 --- a/app/javascript/mastodon/features/status/containers/detailed_status_container.js +++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js @@ -74,12 +74,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onModalReblog (status, privacy) { - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else { if (e.shiftKey || !boostModal) { this.onModalReblog(status); diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 3a9bf524f8..48f045a4af 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -299,7 +299,7 @@ class Status extends ImmutablePureComponent { }; handleModalReblog = (status, privacy) => { - this.props.dispatch(reblog(status, privacy)); + this.props.dispatch(reblog(status.id, privacy)); }; handleReblogClick = (status, e) => { @@ -308,7 +308,7 @@ class Status extends ImmutablePureComponent { if (signedIn) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else { if ((e && e.shiftKey) || !boostModal) { this.handleModalReblog(status); diff --git a/app/javascript/mastodon/reducers/statuses.js b/app/javascript/mastodon/reducers/statuses.js index 683fe848f7..1da1c9cf2f 100644 --- a/app/javascript/mastodon/reducers/statuses.js +++ b/app/javascript/mastodon/reducers/statuses.js @@ -3,10 +3,6 @@ import { Map as ImmutableMap, fromJS } from 'immutable'; import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer'; import { normalizeStatusTranslation } from '../actions/importer/normalizer'; import { - REBLOG_REQUEST, - REBLOG_FAIL, - UNREBLOG_REQUEST, - UNREBLOG_FAIL, FAVOURITE_REQUEST, FAVOURITE_FAIL, UNFAVOURITE_REQUEST, @@ -16,6 +12,10 @@ import { UNBOOKMARK_REQUEST, UNBOOKMARK_FAIL, } from '../actions/interactions'; +import { + reblog, + unreblog, +} from '../actions/interactions_typed'; import { STATUS_MUTE_SUCCESS, STATUS_UNMUTE_SUCCESS, @@ -65,6 +65,7 @@ const statusTranslateUndo = (state, id) => { const initialState = ImmutableMap(); +/** @type {import('@reduxjs/toolkit').Reducer} */ export default function statuses(state = initialState, action) { switch(action.type) { case STATUS_FETCH_REQUEST: @@ -91,14 +92,6 @@ export default function statuses(state = initialState, action) { return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], false); case UNBOOKMARK_FAIL: return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], true); - case REBLOG_REQUEST: - return state.setIn([action.status.get('id'), 'reblogged'], true); - case REBLOG_FAIL: - return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false); - case UNREBLOG_REQUEST: - return state.setIn([action.status.get('id'), 'reblogged'], false); - case UNREBLOG_FAIL: - return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], true); case STATUS_MUTE_SUCCESS: return state.setIn([action.id, 'muted'], true); case STATUS_UNMUTE_SUCCESS: @@ -128,6 +121,15 @@ export default function statuses(state = initialState, action) { case STATUS_TRANSLATE_UNDO: return statusTranslateUndo(state, action.id); default: - return state; + if(reblog.pending.match(action)) + return state.setIn([action.meta.params.statusId, 'reblogged'], true); + else if(reblog.rejected.match(action)) + return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], false); + else if(unreblog.pending.match(action)) + return state.setIn([action.meta.params.statusId, 'reblogged'], false); + else if(unreblog.rejected.match(action)) + return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], true); + else + return state; } } diff --git a/app/javascript/mastodon/store/typed_functions.ts b/app/javascript/mastodon/store/typed_functions.ts index b66d7545c5..4b07a55610 100644 --- a/app/javascript/mastodon/store/typed_functions.ts +++ b/app/javascript/mastodon/store/typed_functions.ts @@ -2,6 +2,8 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { useDispatch, useSelector } from 'react-redux'; +import type { BaseThunkAPI } from '@reduxjs/toolkit/dist/createAsyncThunk'; + import type { AppDispatch, RootState } from './store'; export const useAppDispatch = useDispatch.withTypes(); @@ -13,8 +15,192 @@ export interface AsyncThunkRejectValue { error?: unknown; } +interface AppMeta { + skipLoading?: boolean; +} + export const createAppAsyncThunk = createAsyncThunk.withTypes<{ state: RootState; dispatch: AppDispatch; rejectValue: AsyncThunkRejectValue; }>(); + +type AppThunkApi = Pick< + BaseThunkAPI< + RootState, + unknown, + AppDispatch, + AsyncThunkRejectValue, + AppMeta, + AppMeta + >, + 'getState' | 'dispatch' +>; + +interface AppThunkOptions { + skipLoading?: boolean; +} + +const createBaseAsyncThunk = createAsyncThunk.withTypes<{ + state: RootState; + dispatch: AppDispatch; + rejectValue: AsyncThunkRejectValue; + fulfilledMeta: AppMeta; + rejectedMeta: AppMeta; +}>(); + +export function createThunk( + name: string, + creator: (arg: Arg, api: AppThunkApi) => Returned | Promise, + options: AppThunkOptions = {}, +) { + return createBaseAsyncThunk( + name, + async ( + arg: Arg, + { getState, dispatch, fulfillWithValue, rejectWithValue }, + ) => { + try { + const result = await creator(arg, { dispatch, getState }); + + return fulfillWithValue(result, { + skipLoading: options.skipLoading, + }); + } catch (error) { + return rejectWithValue({ error }, { skipLoading: true }); + } + }, + { + getPendingMeta() { + if (options.skipLoading) return { skipLoading: true }; + return {}; + }, + }, + ); +} + +const discardLoadDataInPayload = Symbol('discardLoadDataInPayload'); +type DiscardLoadData = typeof discardLoadDataInPayload; + +type OnData = ( + data: LoadDataResult, + api: AppThunkApi & { + discardLoadData: DiscardLoadData; + }, +) => ReturnedData | DiscardLoadData | Promise; + +// Overload when there is no `onData` method, the payload is the `onData` result +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], +>( + name: string, + loadData: (...args: Args) => Promise, + thunkOptions?: AppThunkOptions, +): ReturnType>; + +// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], +>( + name: string, + loadData: (...args: Args) => Promise, + onDataOrThunkOptions?: + | AppThunkOptions + | OnData, + thunkOptions?: AppThunkOptions, +): ReturnType>; + +// Overload when the `onData` method returns nothing, then the mayload is the `onData` result +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], +>( + name: string, + loadData: (...args: Args) => Promise, + onDataOrThunkOptions?: AppThunkOptions | OnData, + thunkOptions?: AppThunkOptions, +): ReturnType>; + +// Overload when there is an `onData` method returning something +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], + Returned, +>( + name: string, + loadData: (...args: Args) => Promise, + onDataOrThunkOptions?: AppThunkOptions | OnData, + thunkOptions?: AppThunkOptions, +): ReturnType>; + +/** + * This function creates a Redux Thunk that handles loading data asynchronously (usually from the API), dispatching `pending`, `fullfilled` and `rejected` actions. + * + * You can run a callback on the `onData` results to either dispatch side effects or modify the payload. + * + * It is a wrapper around RTK's [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk) + * @param name Prefix for the actions types + * @param loadData Function that loads the data. It's arguments will become the thunk's arguments + * @param onDataOrThunkOptions + * Callback called on the results from `loadData`. + * + * First argument will be the return from `loadData`. + * + * Second argument is an object with: `dispatch`, `getState` and `discardLoadData`. + * It can return: + * - `undefined` (or no explicit return), meaning that the `onData` results will be the payload + * - `discardLoadData` to discard the `onData` results and return an empty payload + * - anything else, which will be the payload + * + * You can also omit this parameter and pass `thunkOptions` directly + * @param maybeThunkOptions + * Additional Mastodon specific options for the thunk. Currently supports: + * - `skipLoading` to avoid showing the loading bar when the request is in progress + * @returns The created thunk + */ +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], + Returned, +>( + name: string, + loadData: (...args: Args) => Promise, + onDataOrThunkOptions?: AppThunkOptions | OnData, + maybeThunkOptions?: AppThunkOptions, +) { + let onData: OnData | undefined; + let thunkOptions: AppThunkOptions | undefined; + + if (typeof onDataOrThunkOptions === 'function') onData = onDataOrThunkOptions; + else if (typeof onDataOrThunkOptions === 'object') + thunkOptions = onDataOrThunkOptions; + + if (maybeThunkOptions) { + thunkOptions = maybeThunkOptions; + } + + return createThunk( + name, + async (arg, { getState, dispatch }) => { + const data = await loadData(...arg); + + if (!onData) return data as Returned; + + const result = await onData(data, { + dispatch, + getState, + discardLoadData: discardLoadDataInPayload, + }); + + // if there is no return in `onData`, we return the `onData` result + if (typeof result === 'undefined') return data as Returned; + // the user explicitely asked to discard the payload + else if (result === discardLoadDataInPayload) + return undefined as Returned; + else return result; + }, + thunkOptions, + ); +} From 133d98fb25e623745326945b3800173c27519d57 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 23 May 2024 19:28:18 +0200 Subject: [PATCH 228/658] Normalize language code of incoming posts (#30403) --- app/lib/activitypub/parser/status_parser.rb | 11 +++- .../activitypub/parser/status_parser_spec.rb | 50 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 spec/lib/activitypub/parser/status_parser_spec.rb diff --git a/app/lib/activitypub/parser/status_parser.rb b/app/lib/activitypub/parser/status_parser.rb index cfc2b8788b..2940aea44b 100644 --- a/app/lib/activitypub/parser/status_parser.rb +++ b/app/lib/activitypub/parser/status_parser.rb @@ -3,6 +3,8 @@ class ActivityPub::Parser::StatusParser include JsonLdHelper + NORMALIZED_LOCALE_NAMES = LanguagesHelper::SUPPORTED_LOCALES.keys.index_by(&:downcase).freeze + # @param [Hash] json # @param [Hash] options # @option options [String] :followers_collection @@ -87,6 +89,13 @@ class ActivityPub::Parser::StatusParser end def language + lang = raw_language_code + lang.presence && NORMALIZED_LOCALE_NAMES.fetch(lang.downcase.to_sym, lang) + end + + private + + def raw_language_code if content_language_map? @object['contentMap'].keys.first elsif name_language_map? @@ -96,8 +105,6 @@ class ActivityPub::Parser::StatusParser end end - private - def audience_to as_array(@object['to'] || @json['to']).map { |x| value_or_id(x) } end diff --git a/spec/lib/activitypub/parser/status_parser_spec.rb b/spec/lib/activitypub/parser/status_parser_spec.rb new file mode 100644 index 0000000000..5d9f008db1 --- /dev/null +++ b/spec/lib/activitypub/parser/status_parser_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ActivityPub::Parser::StatusParser do + subject { described_class.new(json) } + + let(:sender) { Fabricate(:account, followers_url: 'http://example.com/followers', domain: 'example.com', uri: 'https://example.com/actor') } + let(:follower) { Fabricate(:account, username: 'bob') } + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: [ActivityPub::TagManager.instance.uri_for(sender), '#foo'].join, + type: 'Create', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: object_json, + }.with_indifferent_access + end + + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), 'post1'].join('/'), + type: 'Note', + to: [ + 'https://www.w3.org/ns/activitystreams#Public', + ActivityPub::TagManager.instance.uri_for(follower), + ], + content: '@bob lorem ipsum', + contentMap: { + EN: '@bob lorem ipsum', + }, + published: 1.hour.ago.utc.iso8601, + updated: 1.hour.ago.utc.iso8601, + tag: { + type: 'Mention', + href: ActivityPub::TagManager.instance.uri_for(follower), + }, + } + end + + it 'correctly parses status' do + expect(subject).to have_attributes( + text: '@bob lorem ipsum', + uri: [ActivityPub::TagManager.instance.uri_for(sender), 'post1'].join('/'), + reply: false, + language: :en + ) + end +end From c465ef75602d1b9c92d640de9971a2798355585f Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 23 May 2024 09:30:48 +0200 Subject: [PATCH 229/658] [Glitch] Fix some API calls that should not use an API token Port 15d307075479cf93ea199be0f25820003ddbe27c to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/api.ts | 4 ++-- app/javascript/flavours/glitch/components/admin/Counter.jsx | 2 +- app/javascript/flavours/glitch/components/admin/Dimension.jsx | 2 +- .../flavours/glitch/components/admin/ImpactReport.jsx | 2 +- .../flavours/glitch/components/admin/ReportReasonSelector.jsx | 4 ++-- app/javascript/flavours/glitch/components/admin/Retention.jsx | 2 +- app/javascript/flavours/glitch/components/admin/Trends.jsx | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/javascript/flavours/glitch/api.ts b/app/javascript/flavours/glitch/api.ts index ccff68c373..2ccf178f00 100644 --- a/app/javascript/flavours/glitch/api.ts +++ b/app/javascript/flavours/glitch/api.ts @@ -40,11 +40,11 @@ const authorizationTokenFromInitialState = (): RawAxiosRequestHeaders => { }; // eslint-disable-next-line import/no-default-export -export default function api() { +export default function api(withAuthorization = true) { return axios.create({ headers: { ...csrfHeader, - ...authorizationTokenFromInitialState(), + ...(withAuthorization ? authorizationTokenFromInitialState() : {}), }, transformResponse: [ diff --git a/app/javascript/flavours/glitch/components/admin/Counter.jsx b/app/javascript/flavours/glitch/components/admin/Counter.jsx index 9bb792fc9d..ce62c93570 100644 --- a/app/javascript/flavours/glitch/components/admin/Counter.jsx +++ b/app/javascript/flavours/glitch/components/admin/Counter.jsx @@ -48,7 +48,7 @@ export default class Counter extends PureComponent { componentDidMount () { const { measure, start_at, end_at, params } = this.props; - api().post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => { + api(false).post('/api/v1/admin/measures', { keys: [measure], start_at, end_at, [measure]: params }).then(res => { this.setState({ loading: false, data: res.data, diff --git a/app/javascript/flavours/glitch/components/admin/Dimension.jsx b/app/javascript/flavours/glitch/components/admin/Dimension.jsx index 793fe2dd76..de24a4bf3c 100644 --- a/app/javascript/flavours/glitch/components/admin/Dimension.jsx +++ b/app/javascript/flavours/glitch/components/admin/Dimension.jsx @@ -26,7 +26,7 @@ export default class Dimension extends PureComponent { componentDidMount () { const { start_at, end_at, dimension, limit, params } = this.props; - api().post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => { + api(false).post('/api/v1/admin/dimensions', { keys: [dimension], start_at, end_at, limit, [dimension]: params }).then(res => { this.setState({ loading: false, data: res.data, diff --git a/app/javascript/flavours/glitch/components/admin/ImpactReport.jsx b/app/javascript/flavours/glitch/components/admin/ImpactReport.jsx index 9ec1460fcf..06d1a6a343 100644 --- a/app/javascript/flavours/glitch/components/admin/ImpactReport.jsx +++ b/app/javascript/flavours/glitch/components/admin/ImpactReport.jsx @@ -27,7 +27,7 @@ export default class ImpactReport extends PureComponent { include_subdomains: true, }; - api().post('/api/v1/admin/measures', { + api(false).post('/api/v1/admin/measures', { keys: ['instance_accounts', 'instance_follows', 'instance_followers'], start_at: null, end_at: null, diff --git a/app/javascript/flavours/glitch/components/admin/ReportReasonSelector.jsx b/app/javascript/flavours/glitch/components/admin/ReportReasonSelector.jsx index 9ff1d30899..323e0b0d39 100644 --- a/app/javascript/flavours/glitch/components/admin/ReportReasonSelector.jsx +++ b/app/javascript/flavours/glitch/components/admin/ReportReasonSelector.jsx @@ -105,7 +105,7 @@ class ReportReasonSelector extends PureComponent { }; componentDidMount() { - api().get('/api/v1/instance').then(res => { + api(false).get('/api/v1/instance').then(res => { this.setState({ rules: res.data.rules, }); @@ -122,7 +122,7 @@ class ReportReasonSelector extends PureComponent { return; } - api().put(`/api/v1/admin/reports/${id}`, { + api(false).put(`/api/v1/admin/reports/${id}`, { category, rule_ids: category === 'violation' ? rule_ids : [], }).catch(err => { diff --git a/app/javascript/flavours/glitch/components/admin/Retention.jsx b/app/javascript/flavours/glitch/components/admin/Retention.jsx index e9f0ea2e0f..e2a19d5844 100644 --- a/app/javascript/flavours/glitch/components/admin/Retention.jsx +++ b/app/javascript/flavours/glitch/components/admin/Retention.jsx @@ -34,7 +34,7 @@ export default class Retention extends PureComponent { componentDidMount () { const { start_at, end_at, frequency } = this.props; - api().post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => { + api(false).post('/api/v1/admin/retention', { start_at, end_at, frequency }).then(res => { this.setState({ loading: false, data: res.data, diff --git a/app/javascript/flavours/glitch/components/admin/Trends.jsx b/app/javascript/flavours/glitch/components/admin/Trends.jsx index d7755fcdbb..b64f3f90ab 100644 --- a/app/javascript/flavours/glitch/components/admin/Trends.jsx +++ b/app/javascript/flavours/glitch/components/admin/Trends.jsx @@ -22,7 +22,7 @@ export default class Trends extends PureComponent { componentDidMount () { const { limit } = this.props; - api().get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => { + api(false).get('/api/v1/admin/trends/tags', { params: { limit } }).then(res => { this.setState({ loading: false, data: res.data, From b6fd14f0e2842eca269ef8962e3c5bd560a76357 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 23 May 2024 20:22:42 +0200 Subject: [PATCH 230/658] Fix `createDataLoadingThunk` and related actions (#30408) --- .../mastodon/actions/account_notes.ts | 3 ++- .../mastodon/actions/interactions_typed.ts | 11 ++++++--- app/javascript/mastodon/api.ts | 6 ++--- app/javascript/mastodon/api/accounts.ts | 2 +- .../mastodon/containers/status_container.jsx | 4 ++-- .../containers/account_note_container.js | 2 +- .../containers/notification_container.js | 4 ++-- .../picture_in_picture/components/footer.jsx | 4 ++-- .../containers/detailed_status_container.js | 4 ++-- .../mastodon/features/status/index.jsx | 4 ++-- app/javascript/mastodon/reducers/statuses.js | 8 +++---- .../mastodon/store/typed_functions.ts | 24 +++++++++---------- 12 files changed, 41 insertions(+), 35 deletions(-) diff --git a/app/javascript/mastodon/actions/account_notes.ts b/app/javascript/mastodon/actions/account_notes.ts index bf4f93dca9..c2ebaf54a4 100644 --- a/app/javascript/mastodon/actions/account_notes.ts +++ b/app/javascript/mastodon/actions/account_notes.ts @@ -3,7 +3,8 @@ import { createDataLoadingThunk } from 'mastodon/store/typed_functions'; export const submitAccountNote = createDataLoadingThunk( 'account_note/submit', - (accountId: string, note: string) => apiSubmitAccountNote(accountId, note), + ({ accountId, note }: { accountId: string; note: string }) => + apiSubmitAccountNote(accountId, note), (relationship) => ({ relationship }), { skipLoading: true }, ); diff --git a/app/javascript/mastodon/actions/interactions_typed.ts b/app/javascript/mastodon/actions/interactions_typed.ts index 5180806087..f58faffa86 100644 --- a/app/javascript/mastodon/actions/interactions_typed.ts +++ b/app/javascript/mastodon/actions/interactions_typed.ts @@ -6,8 +6,13 @@ import { importFetchedStatus } from './importer'; export const reblog = createDataLoadingThunk( 'status/reblog', - (statusId: string, visibility: StatusVisibility) => - apiReblog(statusId, visibility), + ({ + statusId, + visibility, + }: { + statusId: string; + visibility: StatusVisibility; + }) => apiReblog(statusId, visibility), (data, { dispatch, discardLoadData }) => { // The reblog API method returns a new status wrapped around the original. In this case we are only // interested in how the original is modified, hence passing it skipping the wrapper @@ -20,7 +25,7 @@ export const reblog = createDataLoadingThunk( export const unreblog = createDataLoadingThunk( 'status/unreblog', - (statusId: string) => apiUnreblog(statusId), + ({ statusId }: { statusId: string }) => apiUnreblog(statusId), (data, { dispatch, discardLoadData }) => { dispatch(importFetchedStatus(data)); diff --git a/app/javascript/mastodon/api.ts b/app/javascript/mastodon/api.ts index 4e5ccef08c..e133125a29 100644 --- a/app/javascript/mastodon/api.ts +++ b/app/javascript/mastodon/api.ts @@ -62,12 +62,12 @@ export default function api(withAuthorization = true) { export async function apiRequest( method: Method, url: string, - params?: unknown, + params?: Record, ) { const { data } = await api().request({ method, - url, - params, + url: '/api/' + url, + data: params, }); return data; diff --git a/app/javascript/mastodon/api/accounts.ts b/app/javascript/mastodon/api/accounts.ts index 51b1f4f8de..3d89e44b26 100644 --- a/app/javascript/mastodon/api/accounts.ts +++ b/app/javascript/mastodon/api/accounts.ts @@ -2,6 +2,6 @@ import { apiRequest } from 'mastodon/api'; import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships'; export const apiSubmitAccountNote = (id: string, value: string) => - apiRequest('post', `/api/v1/accounts/${id}/note`, { + apiRequest('post', `v1/accounts/${id}/note`, { comment: value, }); diff --git a/app/javascript/mastodon/containers/status_container.jsx b/app/javascript/mastodon/containers/status_container.jsx index 0174e5a02c..4a9b525777 100644 --- a/app/javascript/mastodon/containers/status_container.jsx +++ b/app/javascript/mastodon/containers/status_container.jsx @@ -96,9 +96,9 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ onModalReblog (status, privacy) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else { - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); } }, diff --git a/app/javascript/mastodon/features/account/containers/account_note_container.js b/app/javascript/mastodon/features/account/containers/account_note_container.js index 9fbe0671c0..1530242d69 100644 --- a/app/javascript/mastodon/features/account/containers/account_note_container.js +++ b/app/javascript/mastodon/features/account/containers/account_note_container.js @@ -11,7 +11,7 @@ const mapStateToProps = (state, { account }) => ({ const mapDispatchToProps = (dispatch, { account }) => ({ onSave (value) { - dispatch(submitAccountNote(account.get('id'), value)); + dispatch(submitAccountNote({ accountId: account.get('id'), note: value })); }, }); diff --git a/app/javascript/mastodon/features/notifications/containers/notification_container.js b/app/javascript/mastodon/features/notifications/containers/notification_container.js index d829cb833e..650acf4ccd 100644 --- a/app/javascript/mastodon/features/notifications/containers/notification_container.js +++ b/app/javascript/mastodon/features/notifications/containers/notification_container.js @@ -39,12 +39,12 @@ const mapDispatchToProps = dispatch => ({ }, onModalReblog (status, privacy) { - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else { if (e.shiftKey || !boostModal) { this.onModalReblog(status); diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx index 1c142f3c10..ba0642da28 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx @@ -123,7 +123,7 @@ class Footer extends ImmutablePureComponent { _performReblog = (status, privacy) => { const { dispatch } = this.props; - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); }; handleReblogClick = e => { @@ -132,7 +132,7 @@ class Footer extends ImmutablePureComponent { if (signedIn) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else if ((e && e.shiftKey) || !boostModal) { this._performReblog(status); } else { diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js index 91bc700e98..c3d4fec4db 100644 --- a/app/javascript/mastodon/features/status/containers/detailed_status_container.js +++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js @@ -74,12 +74,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onModalReblog (status, privacy) { - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else { if (e.shiftKey || !boostModal) { this.onModalReblog(status); diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx index 48f045a4af..7f37cb50d2 100644 --- a/app/javascript/mastodon/features/status/index.jsx +++ b/app/javascript/mastodon/features/status/index.jsx @@ -299,7 +299,7 @@ class Status extends ImmutablePureComponent { }; handleModalReblog = (status, privacy) => { - this.props.dispatch(reblog(status.id, privacy)); + this.props.dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); }; handleReblogClick = (status, e) => { @@ -308,7 +308,7 @@ class Status extends ImmutablePureComponent { if (signedIn) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else { if ((e && e.shiftKey) || !boostModal) { this.handleModalReblog(status); diff --git a/app/javascript/mastodon/reducers/statuses.js b/app/javascript/mastodon/reducers/statuses.js index 1da1c9cf2f..ca766f73a3 100644 --- a/app/javascript/mastodon/reducers/statuses.js +++ b/app/javascript/mastodon/reducers/statuses.js @@ -122,13 +122,13 @@ export default function statuses(state = initialState, action) { return statusTranslateUndo(state, action.id); default: if(reblog.pending.match(action)) - return state.setIn([action.meta.params.statusId, 'reblogged'], true); + return state.setIn([action.meta.arg.statusId, 'reblogged'], true); else if(reblog.rejected.match(action)) - return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], false); + return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], false); else if(unreblog.pending.match(action)) - return state.setIn([action.meta.params.statusId, 'reblogged'], false); + return state.setIn([action.meta.arg.statusId, 'reblogged'], false); else if(unreblog.rejected.match(action)) - return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], true); + return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], true); else return state; } diff --git a/app/javascript/mastodon/store/typed_functions.ts b/app/javascript/mastodon/store/typed_functions.ts index 4b07a55610..0392f373c0 100644 --- a/app/javascript/mastodon/store/typed_functions.ts +++ b/app/javascript/mastodon/store/typed_functions.ts @@ -92,20 +92,20 @@ type OnData = ( // Overload when there is no `onData` method, the payload is the `onData` result export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, thunkOptions?: AppThunkOptions, ): ReturnType>; // Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, onDataOrThunkOptions?: | AppThunkOptions | OnData, @@ -115,10 +115,10 @@ export function createDataLoadingThunk< // Overload when the `onData` method returns nothing, then the mayload is the `onData` result export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, onDataOrThunkOptions?: AppThunkOptions | OnData, thunkOptions?: AppThunkOptions, ): ReturnType>; @@ -126,11 +126,11 @@ export function createDataLoadingThunk< // Overload when there is an `onData` method returning something export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, Returned, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, onDataOrThunkOptions?: AppThunkOptions | OnData, thunkOptions?: AppThunkOptions, ): ReturnType>; @@ -142,7 +142,7 @@ export function createDataLoadingThunk< * * It is a wrapper around RTK's [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk) * @param name Prefix for the actions types - * @param loadData Function that loads the data. It's arguments will become the thunk's arguments + * @param loadData Function that loads the data. It's (object) argument will become the thunk's argument * @param onDataOrThunkOptions * Callback called on the results from `loadData`. * @@ -162,11 +162,11 @@ export function createDataLoadingThunk< */ export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, Returned, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, onDataOrThunkOptions?: AppThunkOptions | OnData, maybeThunkOptions?: AppThunkOptions, ) { @@ -184,7 +184,7 @@ export function createDataLoadingThunk< return createThunk( name, async (arg, { getState, dispatch }) => { - const data = await loadData(...arg); + const data = await loadData(arg); if (!onData) return data as Returned; From 8d6058b40a8953e16338b57f5ba0e17fc07a1bd2 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 23 May 2024 11:50:13 +0200 Subject: [PATCH 231/658] [Glitch] Proposal: a modern & typed way of writing Redux actions doing API requests Port 10ec421dd4e0da987e69a3dd7f4f696f9c5878e0 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/account_notes.ts | 21 +- .../flavours/glitch/actions/interactions.js | 86 +------- .../glitch/actions/interactions_typed.ts | 30 +++ app/javascript/flavours/glitch/api.ts | 16 +- .../flavours/glitch/api/accounts.ts | 7 + .../flavours/glitch/api/interactions.ts | 10 + .../glitch/containers/status_container.js | 4 +- .../containers/account_note_container.js | 2 +- .../containers/notification_container.js | 4 +- .../picture_in_picture/components/footer.jsx | 4 +- .../containers/detailed_status_container.js | 4 +- .../flavours/glitch/features/status/index.jsx | 4 +- .../flavours/glitch/reducers/statuses.js | 28 +-- .../flavours/glitch/store/typed_functions.ts | 186 ++++++++++++++++++ 14 files changed, 281 insertions(+), 125 deletions(-) create mode 100644 app/javascript/flavours/glitch/actions/interactions_typed.ts create mode 100644 app/javascript/flavours/glitch/api/accounts.ts create mode 100644 app/javascript/flavours/glitch/api/interactions.ts diff --git a/app/javascript/flavours/glitch/actions/account_notes.ts b/app/javascript/flavours/glitch/actions/account_notes.ts index b3e79a92c6..9b05ae06c2 100644 --- a/app/javascript/flavours/glitch/actions/account_notes.ts +++ b/app/javascript/flavours/glitch/actions/account_notes.ts @@ -1,18 +1,9 @@ -import type { ApiRelationshipJSON } from 'flavours/glitch/api_types/relationships'; -import { createAppAsyncThunk } from 'flavours/glitch/store/typed_functions'; +import { apiSubmitAccountNote } from 'flavours/glitch/api/accounts'; +import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions'; -import api from '../api'; - -export const submitAccountNote = createAppAsyncThunk( +export const submitAccountNote = createDataLoadingThunk( 'account_note/submit', - async (args: { id: string; value: string }) => { - const response = await api().post( - `/api/v1/accounts/${args.id}/note`, - { - comment: args.value, - }, - ); - - return { relationship: response.data }; - }, + (accountId: string, note: string) => apiSubmitAccountNote(accountId, note), + (relationship) => ({ relationship }), + { skipLoading: true }, ); diff --git a/app/javascript/flavours/glitch/actions/interactions.js b/app/javascript/flavours/glitch/actions/interactions.js index fe7c911b61..57f2459c01 100644 --- a/app/javascript/flavours/glitch/actions/interactions.js +++ b/app/javascript/flavours/glitch/actions/interactions.js @@ -3,10 +3,6 @@ import api, { getLinks } from '../api'; import { fetchRelationships } from './accounts'; import { importFetchedAccounts, importFetchedStatus } from './importer'; -export const REBLOG_REQUEST = 'REBLOG_REQUEST'; -export const REBLOG_SUCCESS = 'REBLOG_SUCCESS'; -export const REBLOG_FAIL = 'REBLOG_FAIL'; - export const REBLOGS_EXPAND_REQUEST = 'REBLOGS_EXPAND_REQUEST'; export const REBLOGS_EXPAND_SUCCESS = 'REBLOGS_EXPAND_SUCCESS'; export const REBLOGS_EXPAND_FAIL = 'REBLOGS_EXPAND_FAIL'; @@ -15,10 +11,6 @@ export const FAVOURITE_REQUEST = 'FAVOURITE_REQUEST'; export const FAVOURITE_SUCCESS = 'FAVOURITE_SUCCESS'; export const FAVOURITE_FAIL = 'FAVOURITE_FAIL'; -export const UNREBLOG_REQUEST = 'UNREBLOG_REQUEST'; -export const UNREBLOG_SUCCESS = 'UNREBLOG_SUCCESS'; -export const UNREBLOG_FAIL = 'UNREBLOG_FAIL'; - export const UNFAVOURITE_REQUEST = 'UNFAVOURITE_REQUEST'; export const UNFAVOURITE_SUCCESS = 'UNFAVOURITE_SUCCESS'; export const UNFAVOURITE_FAIL = 'UNFAVOURITE_FAIL'; @@ -51,83 +43,7 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST'; export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS'; export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL'; -export function reblog(status, visibility) { - return function (dispatch) { - dispatch(reblogRequest(status)); - - api().post(`/api/v1/statuses/${status.get('id')}/reblog`, { visibility }).then(function (response) { - // The reblog API method returns a new status wrapped around the original. In this case we are only - // interested in how the original is modified, hence passing it skipping the wrapper - dispatch(importFetchedStatus(response.data.reblog)); - dispatch(reblogSuccess(status)); - }).catch(function (error) { - dispatch(reblogFail(status, error)); - }); - }; -} - -export function unreblog(status) { - return (dispatch) => { - dispatch(unreblogRequest(status)); - - api().post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { - dispatch(importFetchedStatus(response.data)); - dispatch(unreblogSuccess(status)); - }).catch(error => { - dispatch(unreblogFail(status, error)); - }); - }; -} - -export function reblogRequest(status) { - return { - type: REBLOG_REQUEST, - status: status, - skipLoading: true, - }; -} - -export function reblogSuccess(status) { - return { - type: REBLOG_SUCCESS, - status: status, - skipLoading: true, - }; -} - -export function reblogFail(status, error) { - return { - type: REBLOG_FAIL, - status: status, - error: error, - skipLoading: true, - }; -} - -export function unreblogRequest(status) { - return { - type: UNREBLOG_REQUEST, - status: status, - skipLoading: true, - }; -} - -export function unreblogSuccess(status) { - return { - type: UNREBLOG_SUCCESS, - status: status, - skipLoading: true, - }; -} - -export function unreblogFail(status, error) { - return { - type: UNREBLOG_FAIL, - status: status, - error: error, - skipLoading: true, - }; -} +export * from "./interactions_typed"; export function favourite(status) { return function (dispatch) { diff --git a/app/javascript/flavours/glitch/actions/interactions_typed.ts b/app/javascript/flavours/glitch/actions/interactions_typed.ts new file mode 100644 index 0000000000..30ae270ea1 --- /dev/null +++ b/app/javascript/flavours/glitch/actions/interactions_typed.ts @@ -0,0 +1,30 @@ +import { apiReblog, apiUnreblog } from 'flavours/glitch/api/interactions'; +import type { StatusVisibility } from 'flavours/glitch/models/status'; +import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions'; + +import { importFetchedStatus } from './importer'; + +export const reblog = createDataLoadingThunk( + 'status/reblog', + (statusId: string, visibility: StatusVisibility) => + apiReblog(statusId, visibility), + (data, { dispatch, discardLoadData }) => { + // The reblog API method returns a new status wrapped around the original. In this case we are only + // interested in how the original is modified, hence passing it skipping the wrapper + dispatch(importFetchedStatus(data.reblog)); + + // The payload is not used in any actions + return discardLoadData; + }, +); + +export const unreblog = createDataLoadingThunk( + 'status/unreblog', + (statusId: string) => apiUnreblog(statusId), + (data, { dispatch, discardLoadData }) => { + dispatch(importFetchedStatus(data)); + + // The payload is not used in any actions + return discardLoadData; + }, +); diff --git a/app/javascript/flavours/glitch/api.ts b/app/javascript/flavours/glitch/api.ts index 2ccf178f00..4e5ccef08c 100644 --- a/app/javascript/flavours/glitch/api.ts +++ b/app/javascript/flavours/glitch/api.ts @@ -1,4 +1,4 @@ -import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios'; +import type { AxiosResponse, Method, RawAxiosRequestHeaders } from 'axios'; import axios from 'axios'; import LinkHeader from 'http-link-header'; @@ -58,3 +58,17 @@ export default function api(withAuthorization = true) { ], }); } + +export async function apiRequest( + method: Method, + url: string, + params?: unknown, +) { + const { data } = await api().request({ + method, + url, + params, + }); + + return data; +} diff --git a/app/javascript/flavours/glitch/api/accounts.ts b/app/javascript/flavours/glitch/api/accounts.ts new file mode 100644 index 0000000000..19abc849b7 --- /dev/null +++ b/app/javascript/flavours/glitch/api/accounts.ts @@ -0,0 +1,7 @@ +import { apiRequest } from 'flavours/glitch/api'; +import type { ApiRelationshipJSON } from 'flavours/glitch/api_types/relationships'; + +export const apiSubmitAccountNote = (id: string, value: string) => + apiRequest('post', `/api/v1/accounts/${id}/note`, { + comment: value, + }); diff --git a/app/javascript/flavours/glitch/api/interactions.ts b/app/javascript/flavours/glitch/api/interactions.ts new file mode 100644 index 0000000000..eaa83b2136 --- /dev/null +++ b/app/javascript/flavours/glitch/api/interactions.ts @@ -0,0 +1,10 @@ +import { apiRequest } from 'flavours/glitch/api'; +import type { Status, StatusVisibility } from 'flavours/glitch/models/status'; + +export const apiReblog = (statusId: string, visibility: StatusVisibility) => + apiRequest<{ reblog: Status }>('post', `v1/statuses/${statusId}/reblog`, { + visibility, + }); + +export const apiUnreblog = (statusId: string) => + apiRequest('post', `v1/statuses/${statusId}/unreblog`); diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js index d304af5ec7..6ae800c037 100644 --- a/app/javascript/flavours/glitch/containers/status_container.js +++ b/app/javascript/flavours/glitch/containers/status_container.js @@ -115,9 +115,9 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ onModalReblog (status, privacy) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else { - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); } }, diff --git a/app/javascript/flavours/glitch/features/account/containers/account_note_container.js b/app/javascript/flavours/glitch/features/account/containers/account_note_container.js index d98a3996d0..2fd7d56735 100644 --- a/app/javascript/flavours/glitch/features/account/containers/account_note_container.js +++ b/app/javascript/flavours/glitch/features/account/containers/account_note_container.js @@ -11,7 +11,7 @@ const mapStateToProps = (state, { account }) => ({ const mapDispatchToProps = (dispatch, { account }) => ({ onSave (value) { - dispatch(submitAccountNote({ id: account.get('id'), value})); + dispatch(submitAccountNote(account.get('id'), value)); }, }); diff --git a/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js b/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js index de5cb2b11e..570f468157 100644 --- a/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js +++ b/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js @@ -36,12 +36,12 @@ const mapDispatchToProps = dispatch => ({ }, onModalReblog (status, privacy) { - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else { if (e.shiftKey || !boostModal) { this.onModalReblog(status); diff --git a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx index 0b6b91fe91..bbcb6d46ba 100644 --- a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx @@ -125,7 +125,7 @@ class Footer extends ImmutablePureComponent { _performReblog = (status, privacy) => { const { dispatch } = this.props; - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); }; handleReblogClick = e => { @@ -134,7 +134,7 @@ class Footer extends ImmutablePureComponent { if (signedIn) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else if ((e && e.shiftKey) || !boostModal) { this._performReblog(status); } else { diff --git a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js index 7e8fe49b23..8fe0fc42e2 100644 --- a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js +++ b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js @@ -71,12 +71,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onModalReblog (status, privacy) { - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else { if (e.shiftKey || !boostModal) { this.onModalReblog(status); diff --git a/app/javascript/flavours/glitch/features/status/index.jsx b/app/javascript/flavours/glitch/features/status/index.jsx index 2656f8afdd..943b48020a 100644 --- a/app/javascript/flavours/glitch/features/status/index.jsx +++ b/app/javascript/flavours/glitch/features/status/index.jsx @@ -346,9 +346,9 @@ class Status extends ImmutablePureComponent { const { dispatch } = this.props; if (status.get('reblogged')) { - dispatch(unreblog(status)); + dispatch(unreblog(status.id)); } else { - dispatch(reblog(status, privacy)); + dispatch(reblog(status.id, privacy)); } }; diff --git a/app/javascript/flavours/glitch/reducers/statuses.js b/app/javascript/flavours/glitch/reducers/statuses.js index 683fe848f7..1da1c9cf2f 100644 --- a/app/javascript/flavours/glitch/reducers/statuses.js +++ b/app/javascript/flavours/glitch/reducers/statuses.js @@ -3,10 +3,6 @@ import { Map as ImmutableMap, fromJS } from 'immutable'; import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer'; import { normalizeStatusTranslation } from '../actions/importer/normalizer'; import { - REBLOG_REQUEST, - REBLOG_FAIL, - UNREBLOG_REQUEST, - UNREBLOG_FAIL, FAVOURITE_REQUEST, FAVOURITE_FAIL, UNFAVOURITE_REQUEST, @@ -16,6 +12,10 @@ import { UNBOOKMARK_REQUEST, UNBOOKMARK_FAIL, } from '../actions/interactions'; +import { + reblog, + unreblog, +} from '../actions/interactions_typed'; import { STATUS_MUTE_SUCCESS, STATUS_UNMUTE_SUCCESS, @@ -65,6 +65,7 @@ const statusTranslateUndo = (state, id) => { const initialState = ImmutableMap(); +/** @type {import('@reduxjs/toolkit').Reducer} */ export default function statuses(state = initialState, action) { switch(action.type) { case STATUS_FETCH_REQUEST: @@ -91,14 +92,6 @@ export default function statuses(state = initialState, action) { return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], false); case UNBOOKMARK_FAIL: return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], true); - case REBLOG_REQUEST: - return state.setIn([action.status.get('id'), 'reblogged'], true); - case REBLOG_FAIL: - return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], false); - case UNREBLOG_REQUEST: - return state.setIn([action.status.get('id'), 'reblogged'], false); - case UNREBLOG_FAIL: - return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'reblogged'], true); case STATUS_MUTE_SUCCESS: return state.setIn([action.id, 'muted'], true); case STATUS_UNMUTE_SUCCESS: @@ -128,6 +121,15 @@ export default function statuses(state = initialState, action) { case STATUS_TRANSLATE_UNDO: return statusTranslateUndo(state, action.id); default: - return state; + if(reblog.pending.match(action)) + return state.setIn([action.meta.params.statusId, 'reblogged'], true); + else if(reblog.rejected.match(action)) + return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], false); + else if(unreblog.pending.match(action)) + return state.setIn([action.meta.params.statusId, 'reblogged'], false); + else if(unreblog.rejected.match(action)) + return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], true); + else + return state; } } diff --git a/app/javascript/flavours/glitch/store/typed_functions.ts b/app/javascript/flavours/glitch/store/typed_functions.ts index b66d7545c5..4b07a55610 100644 --- a/app/javascript/flavours/glitch/store/typed_functions.ts +++ b/app/javascript/flavours/glitch/store/typed_functions.ts @@ -2,6 +2,8 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { useDispatch, useSelector } from 'react-redux'; +import type { BaseThunkAPI } from '@reduxjs/toolkit/dist/createAsyncThunk'; + import type { AppDispatch, RootState } from './store'; export const useAppDispatch = useDispatch.withTypes(); @@ -13,8 +15,192 @@ export interface AsyncThunkRejectValue { error?: unknown; } +interface AppMeta { + skipLoading?: boolean; +} + export const createAppAsyncThunk = createAsyncThunk.withTypes<{ state: RootState; dispatch: AppDispatch; rejectValue: AsyncThunkRejectValue; }>(); + +type AppThunkApi = Pick< + BaseThunkAPI< + RootState, + unknown, + AppDispatch, + AsyncThunkRejectValue, + AppMeta, + AppMeta + >, + 'getState' | 'dispatch' +>; + +interface AppThunkOptions { + skipLoading?: boolean; +} + +const createBaseAsyncThunk = createAsyncThunk.withTypes<{ + state: RootState; + dispatch: AppDispatch; + rejectValue: AsyncThunkRejectValue; + fulfilledMeta: AppMeta; + rejectedMeta: AppMeta; +}>(); + +export function createThunk( + name: string, + creator: (arg: Arg, api: AppThunkApi) => Returned | Promise, + options: AppThunkOptions = {}, +) { + return createBaseAsyncThunk( + name, + async ( + arg: Arg, + { getState, dispatch, fulfillWithValue, rejectWithValue }, + ) => { + try { + const result = await creator(arg, { dispatch, getState }); + + return fulfillWithValue(result, { + skipLoading: options.skipLoading, + }); + } catch (error) { + return rejectWithValue({ error }, { skipLoading: true }); + } + }, + { + getPendingMeta() { + if (options.skipLoading) return { skipLoading: true }; + return {}; + }, + }, + ); +} + +const discardLoadDataInPayload = Symbol('discardLoadDataInPayload'); +type DiscardLoadData = typeof discardLoadDataInPayload; + +type OnData = ( + data: LoadDataResult, + api: AppThunkApi & { + discardLoadData: DiscardLoadData; + }, +) => ReturnedData | DiscardLoadData | Promise; + +// Overload when there is no `onData` method, the payload is the `onData` result +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], +>( + name: string, + loadData: (...args: Args) => Promise, + thunkOptions?: AppThunkOptions, +): ReturnType>; + +// Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], +>( + name: string, + loadData: (...args: Args) => Promise, + onDataOrThunkOptions?: + | AppThunkOptions + | OnData, + thunkOptions?: AppThunkOptions, +): ReturnType>; + +// Overload when the `onData` method returns nothing, then the mayload is the `onData` result +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], +>( + name: string, + loadData: (...args: Args) => Promise, + onDataOrThunkOptions?: AppThunkOptions | OnData, + thunkOptions?: AppThunkOptions, +): ReturnType>; + +// Overload when there is an `onData` method returning something +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], + Returned, +>( + name: string, + loadData: (...args: Args) => Promise, + onDataOrThunkOptions?: AppThunkOptions | OnData, + thunkOptions?: AppThunkOptions, +): ReturnType>; + +/** + * This function creates a Redux Thunk that handles loading data asynchronously (usually from the API), dispatching `pending`, `fullfilled` and `rejected` actions. + * + * You can run a callback on the `onData` results to either dispatch side effects or modify the payload. + * + * It is a wrapper around RTK's [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk) + * @param name Prefix for the actions types + * @param loadData Function that loads the data. It's arguments will become the thunk's arguments + * @param onDataOrThunkOptions + * Callback called on the results from `loadData`. + * + * First argument will be the return from `loadData`. + * + * Second argument is an object with: `dispatch`, `getState` and `discardLoadData`. + * It can return: + * - `undefined` (or no explicit return), meaning that the `onData` results will be the payload + * - `discardLoadData` to discard the `onData` results and return an empty payload + * - anything else, which will be the payload + * + * You can also omit this parameter and pass `thunkOptions` directly + * @param maybeThunkOptions + * Additional Mastodon specific options for the thunk. Currently supports: + * - `skipLoading` to avoid showing the loading bar when the request is in progress + * @returns The created thunk + */ +export function createDataLoadingThunk< + LoadDataResult, + Args extends readonly unknown[], + Returned, +>( + name: string, + loadData: (...args: Args) => Promise, + onDataOrThunkOptions?: AppThunkOptions | OnData, + maybeThunkOptions?: AppThunkOptions, +) { + let onData: OnData | undefined; + let thunkOptions: AppThunkOptions | undefined; + + if (typeof onDataOrThunkOptions === 'function') onData = onDataOrThunkOptions; + else if (typeof onDataOrThunkOptions === 'object') + thunkOptions = onDataOrThunkOptions; + + if (maybeThunkOptions) { + thunkOptions = maybeThunkOptions; + } + + return createThunk( + name, + async (arg, { getState, dispatch }) => { + const data = await loadData(...arg); + + if (!onData) return data as Returned; + + const result = await onData(data, { + dispatch, + getState, + discardLoadData: discardLoadDataInPayload, + }); + + // if there is no return in `onData`, we return the `onData` result + if (typeof result === 'undefined') return data as Returned; + // the user explicitely asked to discard the payload + else if (result === discardLoadDataInPayload) + return undefined as Returned; + else return result; + }, + thunkOptions, + ); +} From e32bfad88a76a1acd42e56c0ad2f83cdfe535aff Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 23 May 2024 20:22:42 +0200 Subject: [PATCH 232/658] [Glitch] Fix `createDataLoadingThunk` and related actions Port b6fd14f0e2842eca269ef8962e3c5bd560a76357 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/account_notes.ts | 3 ++- .../glitch/actions/interactions_typed.ts | 11 ++++++--- app/javascript/flavours/glitch/api.ts | 6 ++--- .../flavours/glitch/api/accounts.ts | 2 +- .../glitch/containers/status_container.js | 4 ++-- .../containers/account_note_container.js | 2 +- .../containers/notification_container.js | 4 ++-- .../picture_in_picture/components/footer.jsx | 4 ++-- .../containers/detailed_status_container.js | 4 ++-- .../flavours/glitch/features/status/index.jsx | 4 ++-- .../flavours/glitch/reducers/statuses.js | 8 +++---- .../flavours/glitch/store/typed_functions.ts | 24 +++++++++---------- 12 files changed, 41 insertions(+), 35 deletions(-) diff --git a/app/javascript/flavours/glitch/actions/account_notes.ts b/app/javascript/flavours/glitch/actions/account_notes.ts index 9b05ae06c2..a71b342b06 100644 --- a/app/javascript/flavours/glitch/actions/account_notes.ts +++ b/app/javascript/flavours/glitch/actions/account_notes.ts @@ -3,7 +3,8 @@ import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions'; export const submitAccountNote = createDataLoadingThunk( 'account_note/submit', - (accountId: string, note: string) => apiSubmitAccountNote(accountId, note), + ({ accountId, note }: { accountId: string; note: string }) => + apiSubmitAccountNote(accountId, note), (relationship) => ({ relationship }), { skipLoading: true }, ); diff --git a/app/javascript/flavours/glitch/actions/interactions_typed.ts b/app/javascript/flavours/glitch/actions/interactions_typed.ts index 30ae270ea1..075fc242e4 100644 --- a/app/javascript/flavours/glitch/actions/interactions_typed.ts +++ b/app/javascript/flavours/glitch/actions/interactions_typed.ts @@ -6,8 +6,13 @@ import { importFetchedStatus } from './importer'; export const reblog = createDataLoadingThunk( 'status/reblog', - (statusId: string, visibility: StatusVisibility) => - apiReblog(statusId, visibility), + ({ + statusId, + visibility, + }: { + statusId: string; + visibility: StatusVisibility; + }) => apiReblog(statusId, visibility), (data, { dispatch, discardLoadData }) => { // The reblog API method returns a new status wrapped around the original. In this case we are only // interested in how the original is modified, hence passing it skipping the wrapper @@ -20,7 +25,7 @@ export const reblog = createDataLoadingThunk( export const unreblog = createDataLoadingThunk( 'status/unreblog', - (statusId: string) => apiUnreblog(statusId), + ({ statusId }: { statusId: string }) => apiUnreblog(statusId), (data, { dispatch, discardLoadData }) => { dispatch(importFetchedStatus(data)); diff --git a/app/javascript/flavours/glitch/api.ts b/app/javascript/flavours/glitch/api.ts index 4e5ccef08c..e133125a29 100644 --- a/app/javascript/flavours/glitch/api.ts +++ b/app/javascript/flavours/glitch/api.ts @@ -62,12 +62,12 @@ export default function api(withAuthorization = true) { export async function apiRequest( method: Method, url: string, - params?: unknown, + params?: Record, ) { const { data } = await api().request({ method, - url, - params, + url: '/api/' + url, + data: params, }); return data; diff --git a/app/javascript/flavours/glitch/api/accounts.ts b/app/javascript/flavours/glitch/api/accounts.ts index 19abc849b7..346b3bc38c 100644 --- a/app/javascript/flavours/glitch/api/accounts.ts +++ b/app/javascript/flavours/glitch/api/accounts.ts @@ -2,6 +2,6 @@ import { apiRequest } from 'flavours/glitch/api'; import type { ApiRelationshipJSON } from 'flavours/glitch/api_types/relationships'; export const apiSubmitAccountNote = (id: string, value: string) => - apiRequest('post', `/api/v1/accounts/${id}/note`, { + apiRequest('post', `v1/accounts/${id}/note`, { comment: value, }); diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js index 6ae800c037..1430a0c845 100644 --- a/app/javascript/flavours/glitch/containers/status_container.js +++ b/app/javascript/flavours/glitch/containers/status_container.js @@ -115,9 +115,9 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({ onModalReblog (status, privacy) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else { - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); } }, diff --git a/app/javascript/flavours/glitch/features/account/containers/account_note_container.js b/app/javascript/flavours/glitch/features/account/containers/account_note_container.js index 2fd7d56735..135e772f3e 100644 --- a/app/javascript/flavours/glitch/features/account/containers/account_note_container.js +++ b/app/javascript/flavours/glitch/features/account/containers/account_note_container.js @@ -11,7 +11,7 @@ const mapStateToProps = (state, { account }) => ({ const mapDispatchToProps = (dispatch, { account }) => ({ onSave (value) { - dispatch(submitAccountNote(account.get('id'), value)); + dispatch(submitAccountNote({ accountId: account.get('id'), note: value })); }, }); diff --git a/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js b/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js index 570f468157..338d27d8d6 100644 --- a/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js +++ b/app/javascript/flavours/glitch/features/notifications/containers/notification_container.js @@ -36,12 +36,12 @@ const mapDispatchToProps = dispatch => ({ }, onModalReblog (status, privacy) { - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else { if (e.shiftKey || !boostModal) { this.onModalReblog(status); diff --git a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx index bbcb6d46ba..13ad86f801 100644 --- a/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/flavours/glitch/features/picture_in_picture/components/footer.jsx @@ -125,7 +125,7 @@ class Footer extends ImmutablePureComponent { _performReblog = (status, privacy) => { const { dispatch } = this.props; - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); }; handleReblogClick = e => { @@ -134,7 +134,7 @@ class Footer extends ImmutablePureComponent { if (signedIn) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else if ((e && e.shiftKey) || !boostModal) { this._performReblog(status); } else { diff --git a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js index 8fe0fc42e2..7cb9735cfe 100644 --- a/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js +++ b/app/javascript/flavours/glitch/features/status/containers/detailed_status_container.js @@ -71,12 +71,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, onModalReblog (status, privacy) { - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); }, onReblog (status, e) { if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else { if (e.shiftKey || !boostModal) { this.onModalReblog(status); diff --git a/app/javascript/flavours/glitch/features/status/index.jsx b/app/javascript/flavours/glitch/features/status/index.jsx index 943b48020a..00639a667e 100644 --- a/app/javascript/flavours/glitch/features/status/index.jsx +++ b/app/javascript/flavours/glitch/features/status/index.jsx @@ -346,9 +346,9 @@ class Status extends ImmutablePureComponent { const { dispatch } = this.props; if (status.get('reblogged')) { - dispatch(unreblog(status.id)); + dispatch(unreblog({ statusId: status.get('id') })); } else { - dispatch(reblog(status.id, privacy)); + dispatch(reblog({ statusId: status.get('id'), visibility: privacy })); } }; diff --git a/app/javascript/flavours/glitch/reducers/statuses.js b/app/javascript/flavours/glitch/reducers/statuses.js index 1da1c9cf2f..ca766f73a3 100644 --- a/app/javascript/flavours/glitch/reducers/statuses.js +++ b/app/javascript/flavours/glitch/reducers/statuses.js @@ -122,13 +122,13 @@ export default function statuses(state = initialState, action) { return statusTranslateUndo(state, action.id); default: if(reblog.pending.match(action)) - return state.setIn([action.meta.params.statusId, 'reblogged'], true); + return state.setIn([action.meta.arg.statusId, 'reblogged'], true); else if(reblog.rejected.match(action)) - return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], false); + return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], false); else if(unreblog.pending.match(action)) - return state.setIn([action.meta.params.statusId, 'reblogged'], false); + return state.setIn([action.meta.arg.statusId, 'reblogged'], false); else if(unreblog.rejected.match(action)) - return state.get(action.meta.params.statusId) === undefined ? state : state.setIn([action.meta.params.statusId, 'reblogged'], true); + return state.get(action.meta.arg.statusId) === undefined ? state : state.setIn([action.meta.arg.statusId, 'reblogged'], true); else return state; } diff --git a/app/javascript/flavours/glitch/store/typed_functions.ts b/app/javascript/flavours/glitch/store/typed_functions.ts index 4b07a55610..0392f373c0 100644 --- a/app/javascript/flavours/glitch/store/typed_functions.ts +++ b/app/javascript/flavours/glitch/store/typed_functions.ts @@ -92,20 +92,20 @@ type OnData = ( // Overload when there is no `onData` method, the payload is the `onData` result export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, thunkOptions?: AppThunkOptions, ): ReturnType>; // Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, onDataOrThunkOptions?: | AppThunkOptions | OnData, @@ -115,10 +115,10 @@ export function createDataLoadingThunk< // Overload when the `onData` method returns nothing, then the mayload is the `onData` result export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, onDataOrThunkOptions?: AppThunkOptions | OnData, thunkOptions?: AppThunkOptions, ): ReturnType>; @@ -126,11 +126,11 @@ export function createDataLoadingThunk< // Overload when there is an `onData` method returning something export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, Returned, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, onDataOrThunkOptions?: AppThunkOptions | OnData, thunkOptions?: AppThunkOptions, ): ReturnType>; @@ -142,7 +142,7 @@ export function createDataLoadingThunk< * * It is a wrapper around RTK's [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk) * @param name Prefix for the actions types - * @param loadData Function that loads the data. It's arguments will become the thunk's arguments + * @param loadData Function that loads the data. It's (object) argument will become the thunk's argument * @param onDataOrThunkOptions * Callback called on the results from `loadData`. * @@ -162,11 +162,11 @@ export function createDataLoadingThunk< */ export function createDataLoadingThunk< LoadDataResult, - Args extends readonly unknown[], + Args extends Record, Returned, >( name: string, - loadData: (...args: Args) => Promise, + loadData: (args: Args) => Promise, onDataOrThunkOptions?: AppThunkOptions | OnData, maybeThunkOptions?: AppThunkOptions, ) { @@ -184,7 +184,7 @@ export function createDataLoadingThunk< return createThunk( name, async (arg, { getState, dispatch }) => { - const data = await loadData(...arg); + const data = await loadData(arg); if (!onData) return data as Returned; From 8ea2726376ed9507072a8e2ec07fdfc219264dad Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 24 May 2024 10:25:42 +0200 Subject: [PATCH 233/658] Fix a leftover argument to `api()` (#30405) --- .../hashtag_timeline/containers/column_settings_container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js b/app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js index be95004cc7..680b44519b 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js +++ b/app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js @@ -15,7 +15,7 @@ const mapStateToProps = (state, { columnId }) => { return { settings: columns.get(index).get('params'), onLoad (value) { - return api(() => state).get('/api/v2/search', { params: { q: value, type: 'hashtags' } }).then(response => { + return api().get('/api/v2/search', { params: { q: value, type: 'hashtags' } }).then(response => { return (response.data.hashtags || []).map((tag) => { return { value: tag.name, label: `#${tag.name}` }; }); From 52a7d053ffc82572d460974b6dde3c6ed776e592 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 10:26:07 +0200 Subject: [PATCH 234/658] fix(deps): update dependency postcss-preset-env to v9.5.14 (#30409) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9f953bb781..df8ba62d82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13592,16 +13592,16 @@ __metadata: languageName: node linkType: hard -"postcss-nesting@npm:^12.1.4": - version: 12.1.4 - resolution: "postcss-nesting@npm:12.1.4" +"postcss-nesting@npm:^12.1.5": + version: 12.1.5 + resolution: "postcss-nesting@npm:12.1.5" dependencies: "@csstools/selector-resolve-nested": "npm:^1.1.0" "@csstools/selector-specificity": "npm:^3.1.1" - postcss-selector-parser: "npm:^6.0.13" + postcss-selector-parser: "npm:^6.1.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/b3408de4c04b58a88a56fa81aeff59b12615c78d4f5a57e09c1ee47e74cff51f8c9cad1684da0059067303cf65b4b688f85f0c5ca8d54af8c4ab998f727ab9fd + checksum: 10c0/8f049fe24dccb186707e065ffb697f9f0633a03b0e1139e9c24656f3d2158a738a51c7b1f405b48fdb8b4f19515ad4ad9d3cd4ec9d9fe1dd4e5f18729bf8e589 languageName: node linkType: hard @@ -13756,8 +13756,8 @@ __metadata: linkType: hard "postcss-preset-env@npm:^9.5.2": - version: 9.5.13 - resolution: "postcss-preset-env@npm:9.5.13" + version: 9.5.14 + resolution: "postcss-preset-env@npm:9.5.14" dependencies: "@csstools/postcss-cascade-layers": "npm:^4.0.6" "@csstools/postcss-color-function": "npm:^3.0.16" @@ -13811,7 +13811,7 @@ __metadata: postcss-image-set-function: "npm:^6.0.3" postcss-lab-function: "npm:^6.0.16" postcss-logical: "npm:^7.0.1" - postcss-nesting: "npm:^12.1.4" + postcss-nesting: "npm:^12.1.5" postcss-opacity-percentage: "npm:^2.0.0" postcss-overflow-shorthand: "npm:^5.0.1" postcss-page-break: "npm:^3.0.4" @@ -13821,7 +13821,7 @@ __metadata: postcss-selector-not: "npm:^7.0.2" peerDependencies: postcss: ^8.4 - checksum: 10c0/5bbb6e87b1b3acc816ef445836f85df5f50ac96bdc3d571952a83794c80863c652d27ab14c66f6b88f86f5664119d49b357e4184162022cc3436676f3fbe833b + checksum: 10c0/8e0c8f5c2e7b8385a770c13185986dc50d7a73b10b98c65c2f86bb4cd2860de722caef8172b1676962dafbbc044d6be1955f2a092e951976a30d4ee33b0d7571 languageName: node linkType: hard @@ -13904,13 +13904,13 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4": - version: 6.0.16 - resolution: "postcss-selector-parser@npm:6.0.16" +"postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-selector-parser@npm:6.1.0" dependencies: cssesc: "npm:^3.0.0" util-deprecate: "npm:^1.0.2" - checksum: 10c0/0e11657cb3181aaf9ff67c2e59427c4df496b4a1b6a17063fae579813f80af79d444bf38f82eeb8b15b4679653fd3089e66ef0283f9aab01874d885e6cf1d2cf + checksum: 10c0/91e9c6434772506bc7f318699dd9d19d32178b52dfa05bed24cb0babbdab54f8fb765d9920f01ac548be0a642aab56bce493811406ceb00ae182bbb53754c473 languageName: node linkType: hard From 54351d01f209447448c57782a034e07968b56a59 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 08:26:38 +0000 Subject: [PATCH 235/658] New Crowdin Translations (automated) (#30410) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ko.json | 2 +- app/javascript/mastodon/locales/nn.json | 5 +++++ config/locales/fi.yml | 1 + config/locales/nn.yml | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 52ce9455a9..b340261479 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -234,7 +234,7 @@ "embed.preview": "이렇게 표시됩니다:", "emoji_button.activity": "활동", "emoji_button.clear": "지우기", - "emoji_button.custom": "사용자 지정", + "emoji_button.custom": "커스텀", "emoji_button.flags": "깃발", "emoji_button.food": "음식과 마실것", "emoji_button.label": "에모지 추가", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 14b355233b..3316e7af81 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -297,6 +297,7 @@ "filter_modal.select_filter.subtitle": "Bruk ein eksisterande kategori eller opprett ein ny", "filter_modal.select_filter.title": "Filtrer dette innlegget", "filter_modal.title.status": "Filtrer eit innlegg", + "filtered_notifications_banner.mentions": "{count, plural, one {omtale} other {omtaler}}", "filtered_notifications_banner.pending_requests": "Varsel frå {count, plural, =0 {ingen} one {ein person} other {# folk}} du kanskje kjenner", "filtered_notifications_banner.title": "Filtrerte varslingar", "firehose.all": "Alle", @@ -307,6 +308,8 @@ "follow_requests.unlocked_explanation": "Sjølv om kontoen din ikkje er låst tenkte dei som driv {domain} at du kanskje ville gå gjennom førespurnadar frå desse kontoane manuelt.", "follow_suggestions.curated_suggestion": "Utvalt av staben", "follow_suggestions.dismiss": "Ikkje vis igjen", + "follow_suggestions.featured_longer": "Hanplukka av gjengen på {domain}", + "follow_suggestions.friends_of_friends_longer": "Populært hjå dei du fylgjer", "follow_suggestions.hints.featured": "Denne profilen er handplukka av folka på {domain}.", "follow_suggestions.hints.friends_of_friends": "Denne profilen er populær hjå dei du fylgjer.", "follow_suggestions.hints.most_followed": "Mange på {domain} fylgjer denne profilen.", @@ -314,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Denne profilen liknar på dei andre profilane du har fylgt i det siste.", "follow_suggestions.personalized_suggestion": "Personleg forslag", "follow_suggestions.popular_suggestion": "Populært forslag", + "follow_suggestions.popular_suggestion_longer": "Populært på {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Liknar på profilar du har fylgt i det siste", "follow_suggestions.view_all": "Vis alle", "follow_suggestions.who_to_follow": "Kven du kan fylgja", "followed_tags": "Fylgde emneknaggar", diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 3a75066d5b..d1fa244672 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -951,6 +951,7 @@ fi: delete: Poista edit_preset: Muokkaa varoituksen esiasetusta empty: Et ole vielä määrittänyt yhtäkään varoitusten esiasetusta. + title: Varoituksen esiasetukset webhooks: add_new: Lisää päätepiste delete: Poista diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 9291ba2c2c..94efdcb15a 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -285,6 +285,7 @@ nn: update_custom_emoji_html: "%{name} oppdaterte emojien %{target}" update_domain_block_html: "%{name} oppdaterte domeneblokkeringa for %{target}" update_ip_block_html: "%{name} endret regel for IP %{target}" + update_report_html: "%{name} oppdaterte rapporten %{target}" update_status_html: "%{name} oppdaterte innlegg av %{target}" update_user_role_html: "%{name} endret %{target} -rolle" deleted_account: sletta konto @@ -950,6 +951,7 @@ nn: delete: Slett edit_preset: Endr åtvaringsoppsett empty: Du har ikke definert noen forhåndsinnstillinger for advarsler enda. + title: Førehandsinnstillingar for varsel webhooks: add_new: Legg til endepunkt delete: Slett From 9305caf1fd5aaeba5c4d980a282c5ca415a7de5c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 08:27:11 +0000 Subject: [PATCH 236/658] fix(deps): update dependency glob to v10.4.1 (#30411) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/yarn.lock b/yarn.lock index df8ba62d82..b4e94dbb34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8936,17 +8936,17 @@ __metadata: linkType: hard "glob@npm:^10.2.2, glob@npm:^10.2.6, glob@npm:^10.3.10, glob@npm:^10.3.7": - version: 10.3.16 - resolution: "glob@npm:10.3.16" + version: 10.4.1 + resolution: "glob@npm:10.4.1" dependencies: foreground-child: "npm:^3.1.0" jackspeak: "npm:^3.1.2" - minimatch: "npm:^9.0.1" - minipass: "npm:^7.0.4" - path-scurry: "npm:^1.11.0" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + path-scurry: "npm:^1.11.1" bin: glob: dist/esm/bin.mjs - checksum: 10c0/f7eb4c3e66f221f0be3967c02527047167967549bdf8ed1bd5f6277d43a35191af4e2bb8c89f07a79664958bae088fd06659e69a0f1de462972f1eab52a715e8 + checksum: 10c0/77f2900ed98b9cc2a0e1901ee5e476d664dae3cd0f1b662b8bfd4ccf00d0edc31a11595807706a274ca10e1e251411bbf2e8e976c82bed0d879a9b89343ed379 languageName: node linkType: hard @@ -11915,7 +11915,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.1, minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.4": version: 9.0.4 resolution: "minimatch@npm:9.0.4" dependencies: @@ -11998,10 +11998,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4": - version: 7.0.4 - resolution: "minipass@npm:7.0.4" - checksum: 10c0/6c7370a6dfd257bf18222da581ba89a5eaedca10e158781232a8b5542a90547540b4b9b7e7f490e4cda43acfbd12e086f0453728ecf8c19e0ef6921bc5958ac5 +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 languageName: node linkType: hard @@ -12824,13 +12824,13 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.11.0": - version: 1.11.0 - resolution: "path-scurry@npm:1.11.0" +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" dependencies: lru-cache: "npm:^10.2.0" minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10c0/a5cd5dfbc6d5bb01d06bc2eb16ccdf303d617865438a21fe15431b8ad334f23351f73259abeb7e4be56f9c68d237b26b4dba51c78b508586035dfc2b55085493 + checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d languageName: node linkType: hard From 9b5055d34dfd079a76493467236d5b4c1496a9a7 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 24 May 2024 04:36:21 -0400 Subject: [PATCH 237/658] Fix `Style/SuperArguments` cop (#30406) --- app/controllers/auth/registrations_controller.rb | 2 +- app/lib/activitypub/serializer.rb | 2 +- app/lib/connection_pool/shared_connection_pool.rb | 2 +- app/lib/rss/channel.rb | 2 +- app/lib/rss/item.rb | 2 +- app/models/concerns/attachmentable.rb | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index acfc0af0d9..f858c0ad93 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -44,7 +44,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController end def build_resource(hash = nil) - super(hash) + super resource.locale = I18n.locale resource.invite_code = @invite&.code if resource.invite_code.blank? diff --git a/app/lib/activitypub/serializer.rb b/app/lib/activitypub/serializer.rb index 1fdc793104..b17ec3fdfb 100644 --- a/app/lib/activitypub/serializer.rb +++ b/app/lib/activitypub/serializer.rb @@ -33,6 +33,6 @@ class ActivityPub::Serializer < ActiveModel::Serializer adapter_options[:named_contexts].merge!(_named_contexts) adapter_options[:context_extensions].merge!(_context_extensions) end - super(adapter_options, options, adapter_instance) + super end end diff --git a/app/lib/connection_pool/shared_connection_pool.rb b/app/lib/connection_pool/shared_connection_pool.rb index 3ca22d0eff..1cfcc5823b 100644 --- a/app/lib/connection_pool/shared_connection_pool.rb +++ b/app/lib/connection_pool/shared_connection_pool.rb @@ -5,7 +5,7 @@ require_relative 'shared_timed_stack' class ConnectionPool::SharedConnectionPool < ConnectionPool def initialize(options = {}, &block) - super(options, &block) + super @available = ConnectionPool::SharedTimedStack.new(@size, &block) end diff --git a/app/lib/rss/channel.rb b/app/lib/rss/channel.rb index 9013ed066a..518ea71405 100644 --- a/app/lib/rss/channel.rb +++ b/app/lib/rss/channel.rb @@ -2,7 +2,7 @@ class RSS::Channel < RSS::Element def initialize - super() + super @root = create_element('channel') end diff --git a/app/lib/rss/item.rb b/app/lib/rss/item.rb index 6739a2c184..8be8d4bf35 100644 --- a/app/lib/rss/item.rb +++ b/app/lib/rss/item.rb @@ -2,7 +2,7 @@ class RSS::Item < RSS::Element def initialize - super() + super @root = create_element('item') end diff --git a/app/models/concerns/attachmentable.rb b/app/models/concerns/attachmentable.rb index 3b7db1fcef..f457f5822b 100644 --- a/app/models/concerns/attachmentable.rb +++ b/app/models/concerns/attachmentable.rb @@ -23,7 +23,7 @@ module Attachmentable included do def self.has_attached_file(name, options = {}) # rubocop:disable Naming/PredicateName - super(name, options) + super send(:"before_#{name}_validate", prepend: true) do attachment = send(name) From 8394a150d787bb9334993ef2ba1e79c9d213be78 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 11:01:42 +0200 Subject: [PATCH 238/658] chore(deps): update dependency rubocop to v1.64.0 (#30404) 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 f1a1d2a938..78023bd7f9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -726,7 +726,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 8) rspec-support (3.13.1) - rubocop (1.63.5) + rubocop (1.64.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) From acc77c3836974473e7c6a423cbd1138479ae197a Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 24 May 2024 15:13:23 +0200 Subject: [PATCH 239/658] Add instrumentation to the search services (#30350) --- Gemfile | 2 ++ Gemfile.lock | 1 + app/services/account_search_service.rb | 22 ++++++++++++++++------ app/services/statuses_search_service.rb | 24 +++++++++++++++++------- app/services/tag_search_service.rb | 24 +++++++++++++++++------- config/initializers/opentelemetry.rb | 2 ++ 6 files changed, 55 insertions(+), 20 deletions(-) diff --git a/Gemfile b/Gemfile index 240dcce95a..d9de331827 100644 --- a/Gemfile +++ b/Gemfile @@ -103,6 +103,8 @@ gem 'rdf-normalize', '~> 0.5' gem 'private_address_check', '~> 0.5' +gem 'opentelemetry-api', '~> 1.2.5' + group :opentelemetry do gem 'opentelemetry-exporter-otlp', '~> 0.26.3', require: false gem 'opentelemetry-instrumentation-active_job', '~> 0.7.1', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 78023bd7f9..ad60eb8be8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -975,6 +975,7 @@ DEPENDENCIES omniauth-rails_csrf_protection (~> 1.0) omniauth-saml (~> 2.0) omniauth_openid_connect (~> 0.6.1) + opentelemetry-api (~> 1.2.5) opentelemetry-exporter-otlp (~> 0.26.3) opentelemetry-instrumentation-active_job (~> 0.7.1) opentelemetry-instrumentation-active_model_serializers (~> 0.20.1) diff --git a/app/services/account_search_service.rb b/app/services/account_search_service.rb index 571a0fa57d..b86c9b9e7e 100644 --- a/app/services/account_search_service.rb +++ b/app/services/account_search_service.rb @@ -151,13 +151,23 @@ class AccountSearchService < BaseService end def call(query, account = nil, options = {}) - @query = query&.strip&.gsub(/\A@/, '') - @limit = options[:limit].to_i - @offset = options[:offset].to_i - @options = options - @account = account + MastodonOTELTracer.in_span('AccountSearchService#call') do |span| + @query = query&.strip&.gsub(/\A@/, '') + @limit = options[:limit].to_i + @offset = options[:offset].to_i + @options = options + @account = account - search_service_results.compact.uniq + span.add_attributes( + 'search.offset' => @offset, + 'search.limit' => @limit, + 'search.backend' => Chewy.enabled? ? 'elasticsearch' : 'database' + ) + + search_service_results.compact.uniq.tap do |results| + span.set_attribute('search.results.count', results.size) + end + end end private diff --git a/app/services/statuses_search_service.rb b/app/services/statuses_search_service.rb index 7d5b0203a0..ab8e28f61c 100644 --- a/app/services/statuses_search_service.rb +++ b/app/services/statuses_search_service.rb @@ -2,14 +2,24 @@ class StatusesSearchService < BaseService def call(query, account = nil, options = {}) - @query = query&.strip - @account = account - @options = options - @limit = options[:limit].to_i - @offset = options[:offset].to_i + MastodonOTELTracer.in_span('StatusesSearchService#call') do |span| + @query = query&.strip + @account = account + @options = options + @limit = options[:limit].to_i + @offset = options[:offset].to_i + convert_deprecated_options! - convert_deprecated_options! - status_search_results + span.add_attributes( + 'search.offset' => @offset, + 'search.limit' => @limit, + 'search.backend' => Chewy.enabled? ? 'elasticsearch' : 'database' + ) + + status_search_results.tap do |results| + span.set_attribute('search.results.count', results.size) + end + end end private diff --git a/app/services/tag_search_service.rb b/app/services/tag_search_service.rb index 929cfd884f..57400b76ad 100644 --- a/app/services/tag_search_service.rb +++ b/app/services/tag_search_service.rb @@ -2,15 +2,25 @@ class TagSearchService < BaseService def call(query, options = {}) - @query = query.strip.delete_prefix('#') - @offset = options.delete(:offset).to_i - @limit = options.delete(:limit).to_i - @options = options + MastodonOTELTracer.in_span('TagSearchService#call') do |span| + @query = query.strip.delete_prefix('#') + @offset = options.delete(:offset).to_i + @limit = options.delete(:limit).to_i + @options = options - results = from_elasticsearch if Chewy.enabled? - results ||= from_database + span.add_attributes( + 'search.offset' => @offset, + 'search.limit' => @limit, + 'search.backend' => Chewy.enabled? ? 'elasticsearch' : 'database' + ) - results + results = from_elasticsearch if Chewy.enabled? + results ||= from_database + + span.set_attribute('search.results.count', results.size) + + results + end end private diff --git a/config/initializers/opentelemetry.rb b/config/initializers/opentelemetry.rb index cf9f0b96f3..d121a95a36 100644 --- a/config/initializers/opentelemetry.rb +++ b/config/initializers/opentelemetry.rb @@ -66,3 +66,5 @@ if ENV.keys.any? { |name| name.match?(/OTEL_.*_ENDPOINT/) } c.service_version = Mastodon::Version.to_s end end + +MastodonOTELTracer = OpenTelemetry.tracer_provider.tracer('mastodon') From 33350cde96187c7356eadfe19a0d602045b0dcbb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 16:44:00 +0200 Subject: [PATCH 240/658] chore(deps): update dependency webmock to v3.23.1 (#30414) 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 ad60eb8be8..5feab4d095 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -877,7 +877,7 @@ GEM webfinger (1.2.0) activesupport httpclient (>= 2.4) - webmock (3.23.0) + webmock (3.23.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) From ccb6aeddacbab950d7d7f1b0d2b64212d7aa99eb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 16:44:03 +0200 Subject: [PATCH 241/658] fix(deps): update babel monorepo to v7.24.6 (#30415) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 1283 ++++++++++++++++++++++++++--------------------------- 1 file changed, 641 insertions(+), 642 deletions(-) diff --git a/yarn.lock b/yarn.lock index b4e94dbb34..03157cce55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,128 +42,128 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.24.2": - version: 7.24.2 - resolution: "@babel/code-frame@npm:7.24.2" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/code-frame@npm:7.24.6" dependencies: - "@babel/highlight": "npm:^7.24.2" + "@babel/highlight": "npm:^7.24.6" picocolors: "npm:^1.0.0" - checksum: 10c0/d1d4cba89475ab6aab7a88242e1fd73b15ecb9f30c109b69752956434d10a26a52cbd37727c4eca104b6d45227bd1dfce39a6a6f4a14c9b2f07f871e968cf406 + checksum: 10c0/c93c6d1763530f415218c31d07359364397f19b70026abdff766164c21ed352a931cf07f3102c5fb9e04792de319e332d68bcb1f7debef601a02197f90f9ba24 languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4": - version: 7.24.4 - resolution: "@babel/compat-data@npm:7.24.4" - checksum: 10c0/9cd8a9cd28a5ca6db5d0e27417d609f95a8762b655e8c9c97fd2de08997043ae99f0139007083c5e607601c6122e8432c85fe391731b19bf26ad458fa0c60dd3 +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/compat-data@npm:7.24.6" + checksum: 10c0/f50abbd4008eb2a5d12139c578809cebbeaeb8e660fb12d546eb2e7c2108ae1836ab8339184a5f5ce0e95bf81bb91e18edce86b387c59db937b01693ec0bc774 languageName: node linkType: hard "@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1, @babel/core@npm:^7.24.4": - version: 7.24.5 - resolution: "@babel/core@npm:7.24.5" + version: 7.24.6 + resolution: "@babel/core@npm:7.24.6" dependencies: "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.24.2" - "@babel/generator": "npm:^7.24.5" - "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-module-transforms": "npm:^7.24.5" - "@babel/helpers": "npm:^7.24.5" - "@babel/parser": "npm:^7.24.5" - "@babel/template": "npm:^7.24.0" - "@babel/traverse": "npm:^7.24.5" - "@babel/types": "npm:^7.24.5" + "@babel/code-frame": "npm:^7.24.6" + "@babel/generator": "npm:^7.24.6" + "@babel/helper-compilation-targets": "npm:^7.24.6" + "@babel/helper-module-transforms": "npm:^7.24.6" + "@babel/helpers": "npm:^7.24.6" + "@babel/parser": "npm:^7.24.6" + "@babel/template": "npm:^7.24.6" + "@babel/traverse": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10c0/e26ba810a77bc8e21579a12fc36c79a0a60554404dc9447f2d64eb1f26d181c48d3b97d39d9f158e9911ec7162a8280acfaf2b4b210e975f0dd4bd4dbb1ee159 + checksum: 10c0/e0762a8daef7f417494d555929418cfacd6848c7fc3310ec00e6dd8cecac20b7f590e760bfc9365d2af07874a3f5599832f9c9ff7f1a9d126a168f77ba67945a languageName: node linkType: hard -"@babel/generator@npm:^7.24.5, @babel/generator@npm:^7.7.2": - version: 7.24.5 - resolution: "@babel/generator@npm:7.24.5" +"@babel/generator@npm:^7.24.6, @babel/generator@npm:^7.7.2": + version: 7.24.6 + resolution: "@babel/generator@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.24.5" + "@babel/types": "npm:^7.24.6" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^2.5.1" - checksum: 10c0/0d64f880150e7dfb92ceff2b4ac865f36aa1e295120920246492ffd0146562dabf79ba8699af1c8833f8a7954818d4d146b7b02f808df4d6024fb99f98b2f78d + checksum: 10c0/8d71a17b386536582354afba53cc784396458a88cc9f05f0c6de0ec99475f6f539943b3566b2e733820c4928236952473831765e483c25d68cc007a6e604d782 languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" +"@babel/helper-annotate-as-pure@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-annotate-as-pure@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/5a80dc364ddda26b334bbbc0f6426cab647381555ef7d0cd32eb284e35b867c012ce6ce7d52a64672ed71383099c99d32765b3d260626527bb0e3470b0f58e45 + "@babel/types": "npm:^7.24.6" + checksum: 10c0/3fe446e3bd37e5e32152279c84ace4e83815e5b88b9e09a82a83974a0bb22e941d89db26b23aaab4c9eb0f9713772c2f6163feffc1bcb055c4cdb6b67e5dc82f languageName: node linkType: hard -"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15" +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.22.15" - checksum: 10c0/2535e3824ca6337f65786bbac98e562f71699f25532cecd196f027d7698b4967a96953d64e36567956658ad1a05ccbdc62d1ba79ee751c79f4f1d2d3ecc2e01c + "@babel/types": "npm:^7.24.6" + checksum: 10c0/d468ba492163bdcf5b6c53248edcf0aaed6194c0f7bdebef4f29ef626e5b03e9fcc7ed737445eb80a961ec6e687c330e1c5242d8a724efb0af002141f3b3e66c languageName: node linkType: hard -"@babel/helper-builder-react-jsx@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/helper-builder-react-jsx@npm:7.22.10" +"@babel/helper-builder-react-jsx@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-builder-react-jsx@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/types": "npm:^7.22.10" - checksum: 10c0/8e2ad2e17dd779ddccec29f6b1de61df1f199694673bdbbae0474878211139f2e574810726110e4d46c1e9a0221af1f2d38bd0398dd20490eb03a24f790602be + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 10c0/93b0500d00f214bc2f7f142ebfa0a634872cadd446bd767f7d58b26ae1b46e1f262b0fe80a9151691463611a3148a69ad28f930295d976bf8ced32c79449a3ce languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.23.6": - version: 7.23.6 - resolution: "@babel/helper-compilation-targets@npm:7.23.6" +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-compilation-targets@npm:7.24.6" dependencies: - "@babel/compat-data": "npm:^7.23.5" - "@babel/helper-validator-option": "npm:^7.23.5" + "@babel/compat-data": "npm:^7.24.6" + "@babel/helper-validator-option": "npm:^7.24.6" browserslist: "npm:^4.22.2" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10c0/ba38506d11185f48b79abf439462ece271d3eead1673dd8814519c8c903c708523428806f05f2ec5efd0c56e4e278698fac967e5a4b5ee842c32415da54bc6fa + checksum: 10c0/4d41150086959f5f4d72d27bae29204192e943537ecb71df1711d1f5d8791358a44f3a5882ed3c8238ba0c874b0b55213af43767e14771765f13b8d15b262432 languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.4, @babel/helper-create-class-features-plugin@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/helper-create-class-features-plugin@npm:7.24.5" +"@babel/helper-create-class-features-plugin@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-create-class-features-plugin@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-member-expression-to-functions": "npm:^7.24.5" - "@babel/helper-optimise-call-expression": "npm:^7.22.5" - "@babel/helper-replace-supers": "npm:^7.24.1" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.24.5" + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-function-name": "npm:^7.24.6" + "@babel/helper-member-expression-to-functions": "npm:^7.24.6" + "@babel/helper-optimise-call-expression": "npm:^7.24.6" + "@babel/helper-replace-supers": "npm:^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" + "@babel/helper-split-export-declaration": "npm:^7.24.6" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/afc72e8075a249663f8024ef1760de4c0b9252bdde16419ac955fa7e15b8d4096ca1e01f796df4fa8cfdb056708886f60b631ad492242a8e47307974fc305920 + checksum: 10c0/e6734671bc6a5f3cca4ec46e4cc70238e5a2fa063e51225c2be572f157119002af419b33ea0f846dbb1307370fe9f3aa92d199449abbea5e88e0262513c8a821 languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.15, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": - version: 7.22.15 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-annotate-as-pure": "npm:^7.24.6" regexpu-core: "npm:^5.3.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/8eba4c1b7b94a83e7a82df5c3e504584ff0ba6ab8710a67ecc2c434a7fb841a29c2f5c94d2de51f25446119a1df538fa90b37bd570db22ddd5e7147fe98277c6 + checksum: 10c0/c6e1b07c94b3b93a3f534039da88bc67ec3156080f1959aa07d5d534e9a640de3533e7ded0516dfcbccde955e91687044e6a950852b1d3f402ac5d5001be56cf languageName: node linkType: hard @@ -182,243 +182,242 @@ __metadata: languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-environment-visitor@npm:7.22.20" - checksum: 10c0/e762c2d8f5d423af89bd7ae9abe35bd4836d2eb401af868a63bbb63220c513c783e25ef001019418560b3fdc6d9a6fb67e6c0b650bcdeb3a2ac44b5c3d2bdd94 +"@babel/helper-environment-visitor@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-environment-visitor@npm:7.24.6" + checksum: 10c0/fdcd18ac505ed71f40c05cc992b648a4495b0aa5310a774492a0f74d8dcf3579691102f516561a651d3de6c3a44fe64bfb3049d11c14c5857634ef1823ea409a languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.22.5, @babel/helper-function-name@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/helper-function-name@npm:7.23.0" +"@babel/helper-function-name@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-function-name@npm:7.24.6" dependencies: - "@babel/template": "npm:^7.22.15" - "@babel/types": "npm:^7.23.0" - checksum: 10c0/d771dd1f3222b120518176733c52b7cadac1c256ff49b1889dbbe5e3fed81db855b8cc4e40d949c9d3eae0e795e8229c1c8c24c0e83f27cfa6ee3766696c6428 + "@babel/template": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 10c0/5ba2f8db789b3f5a2b2239300a217aa212e303cd7bfad9c8b90563807f49215e8c679e8f8f177b6aaca2038038e29bc702b83839e1f7b4896d79c44a75cac97a languageName: node linkType: hard -"@babel/helper-hoist-variables@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-hoist-variables@npm:7.22.5" +"@babel/helper-hoist-variables@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-hoist-variables@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/60a3077f756a1cd9f14eb89f0037f487d81ede2b7cfe652ea6869cd4ec4c782b0fb1de01b8494b9a2d2050e3d154d7d5ad3be24806790acfb8cbe2073bf1e208 + "@babel/types": "npm:^7.24.6" + checksum: 10c0/e10ec6b864aaa419ec4934f5fcb5d0cfcc9d0657584a1b6c3c42ada949d44ca6bffcdab433a90ada4396c747e551cca31ba0e565ea005ab3f50964e3817bf6cf languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.23.0, @babel/helper-member-expression-to-functions@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/helper-member-expression-to-functions@npm:7.24.5" +"@babel/helper-member-expression-to-functions@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.24.5" - checksum: 10c0/a3c0276a1ede8648a0e6fd86ad846cd57421d05eddfa29446b8b5a013db650462022b9ec1e65ea32c747d0542d729c80866830697f94fb12d603e87c51f080a5 + "@babel/types": "npm:^7.24.6" + checksum: 10c0/7595f62978f55921b24de6ed5252fcedbffacfb8271f71e092f38724179ba554cb3a24a4764a1a3890b8a53504c2bee9c99eab81f1f365582739f566c8e28eaa languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.0.0-beta.49, @babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.24.1, @babel/helper-module-imports@npm:^7.24.3": - version: 7.24.3 - resolution: "@babel/helper-module-imports@npm:7.24.3" +"@babel/helper-module-imports@npm:^7.0.0-beta.49, @babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-module-imports@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.24.0" - checksum: 10c0/052c188adcd100f5e8b6ff0c9643ddaabc58b6700d3bbbc26804141ad68375a9f97d9d173658d373d31853019e65f62610239e3295cdd58e573bdcb2fded188d + "@babel/types": "npm:^7.24.6" + checksum: 10c0/e0db3fbfcd963d138f0792ff626f940a576fcf212d02b8fe6478dccf3421bd1c2a76f8e69c7450c049985e7b63b30be309a24eeeb6ad7c2137a31b676a095a84 languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.23.3, @babel/helper-module-transforms@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/helper-module-transforms@npm:7.24.5" +"@babel/helper-module-transforms@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-module-transforms@npm:7.24.6" dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-module-imports": "npm:^7.24.3" - "@babel/helper-simple-access": "npm:^7.24.5" - "@babel/helper-split-export-declaration": "npm:^7.24.5" - "@babel/helper-validator-identifier": "npm:^7.24.5" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-module-imports": "npm:^7.24.6" + "@babel/helper-simple-access": "npm:^7.24.6" + "@babel/helper-split-export-declaration": "npm:^7.24.6" + "@babel/helper-validator-identifier": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/6e77d72f62b7e87abaea800ea0bccd4d54cde26485750969f5f493c032eb63251eb50c3522cace557781565d51c1d0c4bcc866407d24becfb109c18fb92c978d + checksum: 10c0/9e2e3d0ddb397b36b9e8c7d94e175a36be8cb888ef370cefef2cdfd53ae1f87d567b268bd90ed9a6c706485a8de3da19cac577657613e9cd17210b91cbdfb00b languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" +"@babel/helper-optimise-call-expression@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-optimise-call-expression@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/31b41a764fc3c585196cf5b776b70cf4705c132e4ce9723f39871f215f2ddbfb2e28a62f9917610f67c8216c1080482b9b05f65dd195dae2a52cef461f2ac7b8 + "@babel/types": "npm:^7.24.6" + checksum: 10c0/7fce2c4ce22c4ba3c2178d1ce85f34fc9bbe286af5ec153b4b6ea9bf2212390359c4a1e8a54551c4daa4688022d619668bdb8c8060cb185c0c9ad02c5247efc9 languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.24.5 - resolution: "@babel/helper-plugin-utils@npm:7.24.5" - checksum: 10c0/4ae40094e6a2f183281213344f4df60c66b16b19a2bc38d2bb11810a6dc0a0e7ec638957d0e433ff8b615775b8f3cd1b7edbf59440d1b50e73c389fc22913377 +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.6, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.24.6 + resolution: "@babel/helper-plugin-utils@npm:7.24.6" + checksum: 10c0/636d3ce8cabc0621c1f78187e1d95f1087209921fa452f76aad06224ef5dffb3d934946f5183109920f32a4b94dd75ac91c63bc52813fee639d10cd54d49ba1f languageName: node linkType: hard -"@babel/helper-remap-async-to-generator@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" +"@babel/helper-remap-async-to-generator@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-remap-async-to-generator@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-wrap-function": "npm:^7.22.20" + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-wrap-function": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/aa93aa74250b636d477e8d863fbe59d4071f8c2654841b7ac608909e480c1cf3ff7d7af5a4038568829ad09d810bb681668cbe497d9c89ba5c352793dc9edf1e + checksum: 10c0/b379b844eba352ac9487d31867e7bb2b8a264057f1739d9161b614145ea6e60969a7a82e75e5e83089e50cf1b6559f53aa085a787942bf40706fee15a2faa33c languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/helper-replace-supers@npm:7.24.1" +"@babel/helper-replace-supers@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-replace-supers@npm:7.24.6" dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-member-expression-to-functions": "npm:^7.23.0" - "@babel/helper-optimise-call-expression": "npm:^7.22.5" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-member-expression-to-functions": "npm:^7.24.6" + "@babel/helper-optimise-call-expression": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/d39a3df7892b7c3c0e307fb229646168a9bd35e26a72080c2530729322600e8cff5f738f44a14860a2358faffa741b6a6a0d6749f113387b03ddbfa0ec10e1a0 + checksum: 10c0/aaf2dfaf25360da1525ecea5979d5afed201b96f0feeed2e15f90883a97776132a720b25039e67fee10a5c537363aea5cc2a46c0f1d13fdb86d0e920244f2da7 languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.22.5, @babel/helper-simple-access@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/helper-simple-access@npm:7.24.5" +"@babel/helper-simple-access@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-simple-access@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.24.5" - checksum: 10c0/d96a0ab790a400f6c2dcbd9457b9ca74b9ba6d0f67ff9cd5bcc73792c8fbbd0847322a0dddbd8987dd98610ee1637c680938c7d83d3ffce7d06d7519d823d996 + "@babel/types": "npm:^7.24.6" + checksum: 10c0/b17e404dd6c9787fc7d558aea5222471a77e29596705f0d10b4c2a58b9d71ff7eae915094204848cc1af99b771553caa69337a768b9abdd82b54a0050ba83eb9 languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/ab7fa2aa709ab49bb8cd86515a1e715a3108c4bb9a616965ba76b43dc346dee66d1004ccf4d222b596b6224e43e04cbc5c3a34459501b388451f8c589fbc3691 + "@babel/types": "npm:^7.24.6" + checksum: 10c0/6928f698362d6082a67ee2bc73991ef6b0cc6b5f2854177389bc8f3c09296580f0ee20134dd1a29dfcb1906ad9e346fa0f7c6fcd7589ab3ff176d4f09504577f languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/helper-split-export-declaration@npm:7.24.5" +"@babel/helper-split-export-declaration@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-split-export-declaration@npm:7.24.6" dependencies: - "@babel/types": "npm:^7.24.5" - checksum: 10c0/d7a812d67d031a348f3fb0e6263ce2dbe6038f81536ba7fb16db385383bcd6542b71833194303bf6d3d0e4f7b6b584c9c8fae8772122e2ce68fc9bdf07f4135d + "@babel/types": "npm:^7.24.6" + checksum: 10c0/53a5dd8691fdffc89cc7fcf5aed0ad1d8bc39796a5782a3d170dcbf249eb5c15cc8a290e8d09615711d18798ad04a7d0694ab5195d35fa651abbc1b9c885d6a8 languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/helper-string-parser@npm:7.24.1" - checksum: 10c0/2f9bfcf8d2f9f083785df0501dbab92770111ece2f90d120352fda6dd2a7d47db11b807d111e6f32aa1ba6d763fe2dc6603d153068d672a5d0ad33ca802632b2 +"@babel/helper-string-parser@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-string-parser@npm:7.24.6" + checksum: 10c0/95115bf676e92c4e99166395649108d97447e6cabef1fabaec8cdbc53a43f27b5df2268ff6534439d405bc1bd06685b163eb3b470455bd49f69159dada414145 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.20, @babel/helper-validator-identifier@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/helper-validator-identifier@npm:7.24.5" - checksum: 10c0/05f957229d89ce95a137d04e27f7d0680d84ae48b6ad830e399db0779341f7d30290f863a93351b4b3bde2166737f73a286ea42856bb07c8ddaa95600d38645c +"@babel/helper-validator-identifier@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-validator-identifier@npm:7.24.6" + checksum: 10c0/d29d2e3fca66c31867a009014169b93f7bc21c8fc1dd7d0b9d85d7a4000670526ff2222d966febb75a6e12f9859a31d1e75b558984e28ecb69651314dd0a6fd1 languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/helper-validator-option@npm:7.23.5" - checksum: 10c0/af45d5c0defb292ba6fd38979e8f13d7da63f9623d8ab9ededc394f67eb45857d2601278d151ae9affb6e03d5d608485806cd45af08b4468a0515cf506510e94 +"@babel/helper-validator-option@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-validator-option@npm:7.24.6" + checksum: 10c0/787268dff5cf77f3b704454b96ab7b58aa4f43b2808247e51859a103a1c28a9c252100f830433f4b37a73f4a61ba745bbeef4cdccbab48c1e9adf037f4ca3491 languageName: node linkType: hard -"@babel/helper-wrap-function@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-wrap-function@npm:7.22.20" +"@babel/helper-wrap-function@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helper-wrap-function@npm:7.24.6" dependencies: - "@babel/helper-function-name": "npm:^7.22.5" - "@babel/template": "npm:^7.22.15" - "@babel/types": "npm:^7.22.19" - checksum: 10c0/97b5f42ff4d305318ff2f99a5f59d3e97feff478333b2d893c4f85456d3c66372070f71d7bf9141f598c8cf2741c49a15918193633c427a88d170d98eb8c46eb + "@babel/helper-function-name": "npm:^7.24.6" + "@babel/template": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 10c0/d32844275a544a8e7c71c13e9832d34d80656aafce659dc6c23b02e14d1c1179d8045125ded5096da1a99de83299ffb48211183d0403da2c8584ed55dc0ab646 languageName: node linkType: hard -"@babel/helpers@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/helpers@npm:7.24.5" +"@babel/helpers@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/helpers@npm:7.24.6" dependencies: - "@babel/template": "npm:^7.24.0" - "@babel/traverse": "npm:^7.24.5" - "@babel/types": "npm:^7.24.5" - checksum: 10c0/0630b0223c3a9a34027ddc05b3bac54d68d5957f84e92d2d4814b00448a76e12f9188f9c85cfce2011696d82a8ffcbd8189da097c0af0181d32eb27eca34185e + "@babel/template": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 10c0/e5b5c0919fd6fa56ae11c15a72962d8de0ac19db524849554af28cf08ac32f9ae5aee49a43146eb150f54418cefb8e890fa2b2f33d029434dc7777dbcdfd5bac languageName: node linkType: hard -"@babel/highlight@npm:^7.24.2": - version: 7.24.2 - resolution: "@babel/highlight@npm:7.24.2" +"@babel/highlight@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/highlight@npm:7.24.6" dependencies: - "@babel/helper-validator-identifier": "npm:^7.22.20" + "@babel/helper-validator-identifier": "npm:^7.24.6" chalk: "npm:^2.4.2" js-tokens: "npm:^4.0.0" picocolors: "npm:^1.0.0" - checksum: 10c0/98ce00321daedeed33a4ed9362dc089a70375ff1b3b91228b9f05e6591d387a81a8cba68886e207861b8871efa0bc997ceabdd9c90f6cce3ee1b2f7f941b42db + checksum: 10c0/5bbc31695e5d44e97feb267f7aaf4c52908560d184ffeb2e2e57aae058d40125592931883889413e19def3326895ddb41ff45e090fa90b459d8c294b4ffc238c languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/parser@npm:7.24.5" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/parser@npm:7.24.6" bin: parser: ./bin/babel-parser.js - checksum: 10c0/8333a6ad5328bad34fa0e12bcee147c3345ea9a438c0909e7c68c6cfbea43c464834ffd7eabd1cbc1c62df0a558e22ffade9f5b29440833ba7b33d96a71f88c0 + checksum: 10c0/cbef70923078a20fe163b03f4a6482be65ed99d409a57f3091a23ce3a575ee75716c30e7ea9f40b692ac5660f34055f4cbeb66a354fad15a6cf1fca35c3496c5 languageName: node linkType: hard -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.5" +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.6" dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-plugin-utils": "npm:^7.24.5" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/b471972dcc4a3ba32821329a57725e2b563421e975d7ffec7fcabd70af0fced6a50bcc9ed2a8cbd4a9ac7c09cfbf43c7116e82f3b9064b33a22309500b632108 + checksum: 10c0/0dbf12de5a7e5d092271124f0d9bff1ceb94871d5563041940512671cd40ab2a93d613715ee37076cd8263cf49579afb805faa3189996c11639bb10d3e9837f1 languageName: node linkType: hard -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.24.1" +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/d4e592e6fc4878654243d2e7b51ea86471b868a8cb09de29e73b65d2b64159990c6c198fd7c9c2af2e38b1cddf70206243792853c47384a84f829dada152f605 + checksum: 10c0/b0a03d4f587e1fa92312c912864a0af3f68bfc87367b7c93770e94f171767d563d7adfca7ad571d20cd755e89e1373e7414973ce30e694e7b6eb8f57d2b1b889 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.1" +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" - "@babel/plugin-transform-optional-chaining": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.13.0 - checksum: 10c0/351c36e45795a7890d610ab9041a52f4078a59429f6e74c281984aa44149a10d43e82b3a8172c703c0d5679471e165d1c02b6d2e45a677958ee301b89403f202 + checksum: 10c0/fdd40fdf7e87f3dbc5396c9a8f92005798865f6f20d2c24c33246ac43aab8df93742b63dfcfcda67c0a5cf1f7b8a987fdbccaceb9ccbb9a67bef10012b522390 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.24.1" +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.24.6" dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/d7dd5a59a54635a3152895dcaa68f3370bb09d1f9906c1e72232ff759159e6be48de4a598a993c986997280a2dc29922a48aaa98020f16439f3f57ad72788354 + checksum: 10c0/cc1e8ee138c71e78ec262a5198d2cf75c305f2fb4ea9771ebd4ded47f51bc1bacbf917db3cb28c681e7499a07f9803ab0bbe5ad50b9576cbe03902189e3871ed languageName: node linkType: hard @@ -497,25 +496,25 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-assertions@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-syntax-import-assertions@npm:7.24.1" +"@babel/plugin-syntax-import-assertions@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/72f0340d73e037f0702c61670054e0af66ece7282c5c2f4ba8de059390fee502de282defdf15959cd9f71aa18dc5c5e4e7a0fde317799a0600c6c4e0a656d82b + checksum: 10c0/8e81c7cd3d5812a3dda32f06f84492a1b5640f42c594619ed57bf4017529889f87bfb4e8e95c50ba1527d89501dae71a0c73770502676545c2cd9ce58ce3258d languageName: node linkType: hard -"@babel/plugin-syntax-import-attributes@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.1" +"@babel/plugin-syntax-import-attributes@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/309634e3335777aee902552b2cf244c4a8050213cc878b3fb9d70ad8cbbff325dc46ac5e5791836ff477ea373b27832238205f6ceaff81f7ea7c4c7e8fbb13bb + checksum: 10c0/c4d8554b89c0daa6d3c430582b98c10a3af2de8eab484082e97cb73f2712780ab6dd8d11d783c4b266efef76f4479abf4944ef8f416a4459b05eecaf438f8774 languageName: node linkType: hard @@ -541,14 +540,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:7, @babel/plugin-syntax-jsx@npm:^7.23.3, @babel/plugin-syntax-jsx@npm:^7.24.1, @babel/plugin-syntax-jsx@npm:^7.7.2": - version: 7.24.1 - resolution: "@babel/plugin-syntax-jsx@npm:7.24.1" +"@babel/plugin-syntax-jsx@npm:7, @babel/plugin-syntax-jsx@npm:^7.24.6, @babel/plugin-syntax-jsx@npm:^7.7.2": + version: 7.24.6 + resolution: "@babel/plugin-syntax-jsx@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6cec76fbfe6ca81c9345c2904d8d9a8a0df222f9269f0962ed6eb2eb8f3f10c2f15e993d1ef09dbaf97726bf1792b5851cf5bd9a769f966a19448df6be95d19a + checksum: 10c0/f00d783a9e2d52f0a8797823a3cbdbe2d0dc09c7235fe8c88e6dce3a02f234f52fb5e976a001cc30b0e2b330590b5680f54436e56d67f9ab05d1e4bdeb3992cd languageName: node linkType: hard @@ -640,14 +639,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.24.1, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.24.1 - resolution: "@babel/plugin-syntax-typescript@npm:7.24.1" +"@babel/plugin-syntax-typescript@npm:^7.24.6, @babel/plugin-syntax-typescript@npm:^7.7.2": + version: 7.24.6 + resolution: "@babel/plugin-syntax-typescript@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/7a81e277dcfe3138847e8e5944e02a42ff3c2e864aea6f33fd9b70d1556d12b0e70f0d56cc1985d353c91bcbf8fe163e6cc17418da21129b7f7f1d8b9ac00c93 + checksum: 10c0/b1eeabf8bebfa78cea559c0a0d55e480fe2ebd799472d1f6bd5afbd2759d02b362d29ad30009c81d5b112797beb987e58a3000d2331adaa4bf03862e1ed18cef languageName: node linkType: hard @@ -663,456 +662,456 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-arrow-functions@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.1" +"@babel/plugin-transform-arrow-functions@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/f44bfacf087dc21b422bab99f4e9344ee7b695b05c947dacae66de05c723ab9d91800be7edc1fa016185e8c819f3aca2b4a5f66d8a4d1e47d9bad80b8fa55b8e + checksum: 10c0/46250eb3f535327825db323740a301b76b882b70979f1fb5f89cbb1a820378ab68ee880b912981dd5276dd116deaaee0f4a2a95f1c9cf537a67749fd4209a2d3 languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.24.3": - version: 7.24.3 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.24.3" +"@babel/plugin-transform-async-generator-functions@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.24.6" dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-remap-async-to-generator": "npm:^7.22.20" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-remap-async-to-generator": "npm:^7.24.6" "@babel/plugin-syntax-async-generators": "npm:^7.8.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/55ceed059f819dcccbfe69600bfa1c055ada466bd54eda117cfdd2cf773dd85799e2f6556e4a559b076e93b9704abcca2aef9d72aad7dc8a5d3d17886052f1d3 + checksum: 10c0/8876431855220ccfbf1ae510a4a7c4e0377b21189d3f73ea6dde5ffd31eee57f03ea2b2d1da59b6a36b6e107e41b38d0c1d1bb015e0d1c2c2fb627962260edb7 languageName: node linkType: hard -"@babel/plugin-transform-async-to-generator@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.1" +"@babel/plugin-transform-async-to-generator@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.6" dependencies: - "@babel/helper-module-imports": "npm:^7.24.1" - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-remap-async-to-generator": "npm:^7.22.20" + "@babel/helper-module-imports": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-remap-async-to-generator": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/3731ba8e83cbea1ab22905031f25b3aeb0b97c6467360a2cc685352f16e7c786417d8883bc747f5a0beff32266bdb12a05b6292e7b8b75967087200a7bc012c4 + checksum: 10c0/52c137668e7a35356c3b1caf25ab3bf90ff61199885bfd9f0232bfe168a53a5cf0ca4c1e283c27e44ad76cc366b73e4ff7042241469d1944c7042fb78c57bfd8 languageName: node linkType: hard -"@babel/plugin-transform-block-scoped-functions@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.1" +"@babel/plugin-transform-block-scoped-functions@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6fbaa85f5204f34845dfc0bebf62fdd3ac5a286241c85651e59d426001e7a1785ac501f154e093e0b8ee49e1f51e3f8b06575a5ae8d4a9406d43e4816bf18c37 + checksum: 10c0/0c761b5e3a2959b63edf47d67f6752e01f24777ad1accd82457a2dca059877f8a8297fbc7a062db6b48836309932f2ac645c507070ef6ad4e765b3600822c048 languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-transform-block-scoping@npm:7.24.5" +"@babel/plugin-transform-block-scoping@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-block-scoping@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.5" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/85997fc8179b7d26e8af30865aeb91789f3bc1f0cd5643ed25f25891ff9c071460ec1220599b19070b424a3b902422f682e9b02e515872540173eae2e25f760c + checksum: 10c0/95c25e501c4553515f92d4e86032a8859a8855cea8aafb6df30f956979caa70af1e126e6dfaf9e51328d1306232ff1e081bda7d84a9aaf23f418d9da120c7018 languageName: node linkType: hard -"@babel/plugin-transform-class-properties@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-class-properties@npm:7.24.1" +"@babel/plugin-transform-class-properties@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-class-properties@npm:7.24.6" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.24.1" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-create-class-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/00dff042ac9df4ae67b5ef98b1137cc72e0a24e6d911dc200540a8cb1f00b4cff367a922aeb22da17da662079f0abcd46ee1c5f4cdf37ceebf6ff1639bb9af27 + checksum: 10c0/ae01e00dd528112d542a77f0f1cf6b43726553d2011bbdec9e4fac441dfa161d44bf14449dc4121b45cc971686a8c652652032594e83c5d6cab8e9fd794eecb2 languageName: node linkType: hard -"@babel/plugin-transform-class-static-block@npm:^7.24.4": - version: 7.24.4 - resolution: "@babel/plugin-transform-class-static-block@npm:7.24.4" +"@babel/plugin-transform-class-static-block@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-class-static-block@npm:7.24.6" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.24.4" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-create-class-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.12.0 - checksum: 10c0/19dfeaf4a2ac03695034f7211a8b5ad89103b224608ac3e91791055107c5fe4d7ebe5d9fbb31b4a91265694af78762260642eb270f4b239c175984ee4b253f80 + checksum: 10c0/425f237faf62b531d973f23ac3eefe3f29c4f6c988c33c2dd660b6dfb61d4ed1e865a5088574742d87ed02437d26aa6ec6b107468b7df35ca9d3082bad742d8f languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-transform-classes@npm:7.24.5" +"@babel/plugin-transform-classes@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-classes@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-plugin-utils": "npm:^7.24.5" - "@babel/helper-replace-supers": "npm:^7.24.1" - "@babel/helper-split-export-declaration": "npm:^7.24.5" + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-compilation-targets": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-function-name": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-replace-supers": "npm:^7.24.6" + "@babel/helper-split-export-declaration": "npm:^7.24.6" globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/4affcbb7cb01fa4764c7a4b534c30fd24a4b68e680a2d6e242dd7ca8726490f0f1426c44797deff84a38a162e0629718900c68d28daffe2b12adf5b4194156a7 + checksum: 10c0/d29c26feea9ad5a64d790aeab1833b7a50d6af2be24140dad7e06510b754b8fe0ffb292d43d96fedaf7765fcb90c0034ac7c42635f814d9235697431076a1cf0 languageName: node linkType: hard -"@babel/plugin-transform-computed-properties@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-computed-properties@npm:7.24.1" +"@babel/plugin-transform-computed-properties@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-computed-properties@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/template": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/template": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/8292c508b656b7722e2c2ca0f6f31339852e3ed2b9b80f6e068a4010e961b431ca109ecd467fc906283f4b1574c1e7b1cb68d35a4dea12079d386c15ff7e0eac + checksum: 10c0/c464144c2eda8d526d70c8d8e3bf30820f591424991452f816617347ef3ccc5d04133c6e903b90c1d832d95d9c8550e5693ea40ea14856ede54fb8e1cd36c5de languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-transform-destructuring@npm:7.24.5" +"@babel/plugin-transform-destructuring@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-destructuring@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.5" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6a37953a95f04b335bf3e2118fb93f50dd9593c658d1b2f8918a380a2ee30f1b420139eccf7ec3873c86a8208527895fcf6b7e21c0e734a6ad6e5d5042eace4d + checksum: 10c0/1fcc064e2b0c45a4340418bd70d2cf2b3644d1215eb975ec14f83e4f7615fdc3948e355db5091f81602f6c3d933f9308caa66232091aad4edd6c16b00240fcc7 languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.1" +"@babel/plugin-transform-dotall-regex@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.6" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/758def705ec5a87ef910280dc2df5d2fda59dc5d4771c1725c7aed0988ae5b79e29aeb48109120301a3e1c6c03dfac84700469de06f38ca92c96834e09eadf5d + checksum: 10c0/4a2c98f1c22a18754c6ada1486563865690008df2536066d8a146fa58eed8515b607e162c7efb0b8fa062d755e77afea145495046cffdb4ea56194d38f489254 languageName: node linkType: hard -"@babel/plugin-transform-duplicate-keys@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.1" +"@babel/plugin-transform-duplicate-keys@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/41072f57f83a6c2b15f3ee0b6779cdca105ff3d98061efe92ac02d6c7b90fdb6e7e293b8a4d5b9c690d9ae5d3ae73e6bde4596dc4d8c66526a0e5e1abc73c88c + checksum: 10c0/44ddba252f0b9f1f0b1ff8d903bbcf8871246670fb2883f65d09d371d403ce9c3e2e582b94b36506c1d042110b464eb3492e53cd1e87c1d479b145bcc01c04fd languageName: node linkType: hard -"@babel/plugin-transform-dynamic-import@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.1" +"@babel/plugin-transform-dynamic-import@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/7e2834780e9b5251ef341854043a89c91473b83c335358620ca721554877e64e416aeb3288a35f03e825c4958e07d5d00ead08c4490fadc276a21fe151d812f1 + checksum: 10c0/b4411f21112127a02aef15103765e207e4c03e7321d7f4de3522fc181cb377c5abc8484cf0169e6c30f2e51e6c602c09894fa6b15643d24f66273833ef34e4a6 languageName: node linkType: hard -"@babel/plugin-transform-exponentiation-operator@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.1" +"@babel/plugin-transform-exponentiation-operator@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.6" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/f0fc4c5a9add25fd6bf23dabe6752e9b7c0a2b2554933dddfd16601245a2ba332b647951079c782bf3b94c6330e3638b9b4e0227f469a7c1c707446ba0eba6c7 + checksum: 10c0/c4f15518a5d1614dfac0dbadfb99b0f36a98c1c1ff1c39794a105c3c87cfce00689e0943fcb13368b43b00b2eebaa01136ea12fb8600a574720853b5a8a11de7 languageName: node linkType: hard -"@babel/plugin-transform-export-namespace-from@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.1" +"@babel/plugin-transform-export-namespace-from@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/510bb23b2423d5fbffef69b356e4050929c21a7627e8194b1506dd935c7d9cbbd696c9ae9d7c3bcd7e6e7b69561b0b290c2d72d446327b40fc20ce40bbca6712 + checksum: 10c0/bff16d1800d7e5b38d3a3c8d404cc14442a37383dff7769dcc599a0723b2507647cafe9ba7d9b52d2e2f02a78bb78d149676d8d8ddf7357b160f4096b89ae9c5 languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-for-of@npm:7.24.1" +"@babel/plugin-transform-for-of@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-for-of@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e4bc92b1f334246e62d4bde079938df940794db564742034f6597f2e38bd426e11ae8c5670448e15dd6e45c462f2a9ab3fa87259bddf7c08553ffd9457fc2b2c + checksum: 10c0/c8def2a160783c5c4a1c136c721fc88aca9cd3757a60f1c885a804b5320edb5f143d3f989f698bdd9aae359fdabab0830dba3d35138cea42988a77d2c72c8443 languageName: node linkType: hard -"@babel/plugin-transform-function-name@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-function-name@npm:7.24.1" +"@babel/plugin-transform-function-name@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-function-name@npm:7.24.6" dependencies: - "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-compilation-targets": "npm:^7.24.6" + "@babel/helper-function-name": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/65c1735ec3b5e43db9b5aebf3c16171c04b3050c92396b9e22dda0d2aaf51f43fdcf147f70a40678fd9a4ee2272a5acec4826e9c21bcf968762f4c184897ad75 + checksum: 10c0/efa6527438ad94df0b7a4c92c33110ec40b086a0aceda567176b150ed291f8eb44b2ce697d8e3e1d4841496c10693add1e88f296418e72a171ead5c76b890a47 languageName: node linkType: hard -"@babel/plugin-transform-json-strings@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-json-strings@npm:7.24.1" +"@babel/plugin-transform-json-strings@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-json-strings@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-json-strings": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/13d9b6a3c31ab4be853b3d49d8d1171f9bd8198562fd75da8f31e7de31398e1cfa6eb1d073bed93c9746e4f9c47a53b20f8f4c255ece3f88c90852ad3181dc2d + checksum: 10c0/46af52dcc16f494c6c11dc22c944f2533623b9d9dfce5097bc0bdb99535ad4c4cfe5bca0d8ce8c39a94202e69d99ee60f546ce0be0ad782b681c7b5b4c9ddd6f languageName: node linkType: hard -"@babel/plugin-transform-literals@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-literals@npm:7.24.1" +"@babel/plugin-transform-literals@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-literals@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/a27cc7d565ee57b5a2bf136fa889c5c2f5988545ae7b3b2c83a7afe5dd37dfac80dca88b1c633c65851ce6af7d2095c04c01228657ce0198f918e64b5ccd01fa + checksum: 10c0/961b64df79a673706d74cf473d1f4646f250b4f8813f9d7ef5d897e30acdacd1ca104584de2e88546289fce055d71bd7559cdb8ad4a2d5e7eea17f3c829faa97 languageName: node linkType: hard -"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.1" +"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/98a2e0843ddfe51443c1bfcf08ba40ad8856fd4f8e397b392a5390a54f257c8c1b9a99d8ffc0fc7e8c55cce45e2cd9c2795a4450303f48f501bcbd662de44554 + checksum: 10c0/0ae7f4098c63f442fd038de6034155bcf20214e7e490e92189decb2980932247b97cb069b11ac8bc471b53f71d6859e607969440d63ff400b8932ee3e05b4958 languageName: node linkType: hard -"@babel/plugin-transform-member-expression-literals@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.1" +"@babel/plugin-transform-member-expression-literals@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/2af731d02aa4c757ef80c46df42264128cbe45bfd15e1812d1a595265b690a44ad036041c406a73411733540e1c4256d8174705ae6b8cfaf757fc175613993fd + checksum: 10c0/ec8908a409bd39d20f0428e35425c9e4c540bad252a0e33e08b84e3bea5088c785531197bdcf049afbdba841325962a93030b7be6da3586cb13d0ca0ebab89c9 languageName: node linkType: hard -"@babel/plugin-transform-modules-amd@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-modules-amd@npm:7.24.1" +"@babel/plugin-transform-modules-amd@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-modules-amd@npm:7.24.6" dependencies: - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-module-transforms": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/71fd04e5e7026e6e52701214b1e9f7508ba371b757e5075fbb938a79235ed66a54ce65f89bb92b59159e9f03f01b392e6c4de6d255b948bec975a90cfd6809ef + checksum: 10c0/074d26c79f517b27a07fef00319aff9705df1e6b41a805db855fe719e0f246b9815d6525cf1c5f0890c7f830dd0b9776e9b2493bbc929a3c23c0dee15f10a514 languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.1" +"@babel/plugin-transform-modules-commonjs@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.6" dependencies: - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-simple-access": "npm:^7.22.5" + "@babel/helper-module-transforms": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-simple-access": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/efb3ea2047604a7eb44a9289311ebb29842fe6510ff8b66a77a60440448c65e1312a60dc48191ed98246bdbd163b5b6f3348a0669bcc0e3809e69c7c776b20fa + checksum: 10c0/4fc790136d066105fa773ffc7e249d88c6f0d0126984ede36fedd51ac2b622b46c08565bcdd1ab62ac10195eeedeaba0d26e7e4c676ed50906cbed16540a4e22 languageName: node linkType: hard -"@babel/plugin-transform-modules-systemjs@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.24.1" +"@babel/plugin-transform-modules-systemjs@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.24.6" dependencies: - "@babel/helper-hoist-variables": "npm:^7.22.5" - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-validator-identifier": "npm:^7.22.20" + "@babel/helper-hoist-variables": "npm:^7.24.6" + "@babel/helper-module-transforms": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-validator-identifier": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/38145f8abe8a4ce2b41adabe5d65eb7bd54a139dc58e2885fec975eb5cf247bd938c1dd9f09145c46dbe57d25dd0ef7f00a020e5eb0cbe8195b2065d51e2d93d + checksum: 10c0/500962e3ac1bb1a9890e94f1967ec9e3aa3d41e22d4a9d1c739918707e4a8936710fd8d0ed4f3a8aad87260f7566b54566bead77977eb21e90124835cb6bcdca languageName: node linkType: hard -"@babel/plugin-transform-modules-umd@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-modules-umd@npm:7.24.1" +"@babel/plugin-transform-modules-umd@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-modules-umd@npm:7.24.6" dependencies: - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-module-transforms": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/14c90c58562b54e17fe4a8ded3f627f9a993648f8378ef00cb2f6c34532032b83290d2ad54c7fff4f0c2cd49091bda780f8cc28926ec4b77a6c2141105a2e699 + checksum: 10c0/73c6cecb4f45ca3f665e2c57b6d04d65358518522dfaffb9b6913c026aeb704281d015324d02bf07f2cb026de6bac9308c62e82979364bd39f3687f752652b0d languageName: node linkType: hard -"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.24.6" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/b0b072bef303670b5a98307bc37d1ac326cb7ad40ea162b89a03c2ffc465451be7ef05be95cb81ed28bfeb29670dc98fe911f793a67bceab18b4cb4c81ef48f3 + checksum: 10c0/92547309d81938488753f87b05a679a7557a1cec253756966044367c268b27311e51efad91724aa3e433cf61626e10bf1008e112998350c2013a87824c4cfe0b languageName: node linkType: hard -"@babel/plugin-transform-new-target@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-new-target@npm:7.24.1" +"@babel/plugin-transform-new-target@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-new-target@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c4cabe628163855f175a8799eb73d692b6f1dc347aae5022af0c253f80c92edb962e48ddccc98b691eff3d5d8e53c9a8f10894c33ba4cebc2e2f8f8fe554fb7a + checksum: 10c0/5e9b9edfbe46489f64013d2bbd422f29acdb8057ccc85e7c759f7cf1415fde6a82ac13a13f0f246defaba6e2f7f4d424178ba78fc02237bdbf7df6692fc1dca8 languageName: node linkType: hard -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.1" +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c8532951506fb031287280cebeef10aa714f8a7cea2b62a13c805f0e0af945ba77a7c87e4bbbe4c37fe973e0e5d5e649cfac7f0374f57efc54cdf9656362a392 + checksum: 10c0/53ab5b16bbcf47e842a48f1f0774d238dae0222c3e1f31653307808048e249ed140cba12dfc280cbc9a577cb3bb5b2f50ca0e3e4ffe5260fcf8c3ca0b83fb21e languageName: node linkType: hard -"@babel/plugin-transform-numeric-separator@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.1" +"@babel/plugin-transform-numeric-separator@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/15e2b83292e586fb4f5b4b4021d4821a806ca6de2b77d5ad6c4e07aa7afa23704e31b4d683dac041afc69ac51b2461b96e8c98e46311cc1faba54c73f235044f + checksum: 10c0/14863e735fc407e065e1574914864a956b8250a84cfb4704592656763c9455d67034c7745e53066725195d9ed042121f424c4aaee00027791640e2639386b701 languageName: node linkType: hard -"@babel/plugin-transform-object-rest-spread@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.5" +"@babel/plugin-transform-object-rest-spread@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.6" dependencies: - "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-plugin-utils": "npm:^7.24.5" + "@babel/helper-compilation-targets": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-transform-parameters": "npm:^7.24.5" + "@babel/plugin-transform-parameters": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/91d7303af9b5744b8f569c1b8e45c9c9322ded05e7ee94e71b9ff2327f0d2c7b5aa87e040697a6baacc2dcb5c5e5e00913087c36f24c006bdaa4f958fd5bfd2d + checksum: 10c0/1a192b9756ebfa0bc69ad5e285d7d0284963b4b95738ca7721354297329d5c1ab4eb05ff5b198cbfffa3ec00e97a15a712aa7a5011d9407478796966aab54527 languageName: node linkType: hard -"@babel/plugin-transform-object-super@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-object-super@npm:7.24.1" +"@babel/plugin-transform-object-super@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-object-super@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-replace-supers": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-replace-supers": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d30e6b9e59a707efd7ed524fc0a8deeea046011a6990250f2e9280516683138e2d13d9c52daf41d78407bdab0378aef7478326f2a15305b773d851cb6e106157 + checksum: 10c0/2e48b9e0a1f3b04b439ede2d0c83bcc5324a81c8bab73c70f0c466cf48061a4ff469f283e2feb17b4cc2e20372c1362253604477ecd77e622192d5d7906aa062 languageName: node linkType: hard -"@babel/plugin-transform-optional-catch-binding@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.1" +"@babel/plugin-transform-optional-catch-binding@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/68408b9ef772d9aa5dccf166c86dc4d2505990ce93e03dcfc65c73fb95c2511248e009ba9ccf5b96405fb85de1c16ad8291016b1cc5689ee4becb1e3050e0ae7 + checksum: 10c0/411db3177b1bffd2f9e5b33a6b62e70158380e67d91ff4725755312e8a0a2f2c3fd340c60005295a672115fb593222ab2d7076266aebced6ef087a5505b6f371 languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.24.1, @babel/plugin-transform-optional-chaining@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.5" +"@babel/plugin-transform-optional-chaining@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.5" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/f4e9446ec69f58f40b7843ce7603cfc50332976e6e794d4ddbe6b24670cd50ebc7766c4e3cbaecf0fbb744e98cbfbb54146f4e966314b1d58511b8bbf3d2722b + checksum: 10c0/8ee5a500a2309444d4fb27979857598e9c91d804fe23217c51cc208b1bc6b9cd0650b355b1ebd625f180c5f1dc4cb89b5f313c982f7c89d90281a69b24a88ccb languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-transform-parameters@npm:7.24.5" +"@babel/plugin-transform-parameters@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-parameters@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.5" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e08b8c46a24b1b21dde7783cb0aeb56ffe9ef6d6f1795649ce76273657158d3bfa5370c6594200ed7d371983b599c8e194b76108dffed9ab5746fe630ef2e8f5 + checksum: 10c0/d9648924b9c0d35a243c0742c22838932a024205c61f4cc419857e5195edd893a33e6be4f2c8fbd89e925051c7cbe8968029ec2d3e7f2f098bfa682f4e2b9731 languageName: node linkType: hard -"@babel/plugin-transform-private-methods@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-private-methods@npm:7.24.1" +"@babel/plugin-transform-private-methods@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-private-methods@npm:7.24.6" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.24.1" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-create-class-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d8e18587d2a8b71a795da5e8841b0e64f1525a99ad73ea8b9caa331bc271d69646e2e1e749fd634321f3df9d126070208ddac22a27ccf070566b2efb74fecd99 + checksum: 10c0/55f93959b2e8aeda818db7cdc7dfdcd5076f5bdc8a819566818004a68969fb7297d617f9d108bf76ac232d6056d9f9d20f73ce10380baa43ff1755c5591aa803 languageName: node linkType: hard -"@babel/plugin-transform-private-property-in-object@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.5" +"@babel/plugin-transform-private-property-in-object@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-create-class-features-plugin": "npm:^7.24.5" - "@babel/helper-plugin-utils": "npm:^7.24.5" + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-create-class-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/de7182bfde298e56c08a5d7ee1156f83c9af8c856bbe2248438848846a4ce544e050666bd0482e16a6006195e8be4923abd14650bef51fa0edd7f82014c2efcd + checksum: 10c0/c9eb9597362b598a91536375a49ba80cdf13461e849680e040898b103f7998c4d33a7832da5afba9fa51e3473f79cf8605f9ace07a887e386b7801797021631b languageName: node linkType: hard -"@babel/plugin-transform-property-literals@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-property-literals@npm:7.24.1" +"@babel/plugin-transform-property-literals@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-property-literals@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/3bf3e01f7bb8215a8b6d0081b6f86fea23e3a4543b619e059a264ede028bc58cdfb0acb2c43271271915a74917effa547bc280ac636a9901fa9f2fb45623f87e + checksum: 10c0/d1195d93406b6c400cdbc9ac57a2b8b58c72cc6480cc03656abfc243be0e2a48133cbb96559c2db95b1c78803daeb538277821540fe19e2a9105905e727ef618 languageName: node linkType: hard @@ -1127,243 +1126,243 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-display-name@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-react-display-name@npm:7.24.1" +"@babel/plugin-transform-react-display-name@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-react-display-name@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/adf1a3cb0df8134533a558a9072a67e34127fd489dfe431c3348a86dd41f3e74861d5d5134bbb68f61a9cdb3f7e79b2acea1346be94ce4d3328a64e5a9e09be1 + checksum: 10c0/e929d054035fa3b7432bd2b3e5cf280ffd8cf60d1ce80c863c5e0b03ad01bf6ae2546575d2da31cca2ab83d9399ac01a351f20e21af5075d9c0d4c893e4a36bd languageName: node linkType: hard "@babel/plugin-transform-react-inline-elements@npm:^7.21.0": - version: 7.24.1 - resolution: "@babel/plugin-transform-react-inline-elements@npm:7.24.1" + version: 7.24.6 + resolution: "@babel/plugin-transform-react-inline-elements@npm:7.24.6" dependencies: - "@babel/helper-builder-react-jsx": "npm:^7.22.10" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-builder-react-jsx": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/83fc6afaebbe82a5b14936f00b6d1ffce1a3d908ac749d5daa43f724d32c98b50807ffc3ce2492c1aa49870189507b751993a4a079b9c3226c9b8aab783d08b6 + checksum: 10c0/b29f32a0c345db24f32569cf7a5626e37dd31c21bb764148757e91f609d41e2d09031ff1ad86e5672d578cf16f513b197ef3ebc8f0650d8314890a34ca68f02c languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-development@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-jsx-development@npm:7.22.5" +"@babel/plugin-transform-react-jsx-development@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.24.6" dependencies: - "@babel/plugin-transform-react-jsx": "npm:^7.22.5" + "@babel/plugin-transform-react-jsx": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/4d2e9e68383238feb873f6111df972df4a2ebf6256d6f787a8772241867efa975b3980f7d75ab7d750e7eaad4bd454e8cc6e106301fd7572dd389e553f5f69d2 + checksum: 10c0/f899ffa65c7f459a682246a346af0e4132929ffe928cb0d02ae08aac1cf3fb01b2f6e944ef1eaca78f14e94eff935e2bf96aad878030c25ff6de2070a8b72448 languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.22.5, @babel/plugin-transform-react-jsx@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/plugin-transform-react-jsx@npm:7.23.4" +"@babel/plugin-transform-react-jsx@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-react-jsx@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-module-imports": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/plugin-syntax-jsx": "npm:^7.23.3" - "@babel/types": "npm:^7.23.4" + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-module-imports": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/plugin-syntax-jsx": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/8851b3adc515cd91bdb06ff3a23a0f81f0069cfef79dfb3fa744da4b7a82e3555ccb6324c4fa71ecf22508db13b9ff6a0ed96675f95fc87903b9fc6afb699580 + checksum: 10c0/6144f56a76529a82077475583a17be8f0b0b461c83673e650f3894e09dbe2bcdfdbfff089eca2e5e239e119f72cd9562749a9af7eb3f2e3266a730da31cd19f2 languageName: node linkType: hard -"@babel/plugin-transform-react-pure-annotations@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.24.1" +"@babel/plugin-transform-react-pure-annotations@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/9eb3056fcaadd63d404fd5652b2a3f693bc4758ba753fee5b5c580c7a64346eeeb94e5a4f77a99c76f3cf06d1f1ad6c227647cd0b1219efe3d00cafa5a6e7b2a + checksum: 10c0/7f83c5a3a275dbb9a291dee4642a3a0f2249265346d8d3cc9324fc9ee063c3e35c3853b52752ece603f0ac92b405deb38c4b5307a99a74d3e1c9c32a2cefa465 languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-regenerator@npm:7.24.1" +"@babel/plugin-transform-regenerator@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-regenerator@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" regenerator-transform: "npm:^0.15.2" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/0a333585d7c0b38d31cc549d0f3cf7c396d1d50b6588a307dc58325505ddd4f5446188bc536c4779431b396251801b3f32d6d8e87db8274bc84e8c41950737f7 + checksum: 10c0/d17eaa97514d583866182420024b8c22da2c6ca822bdbf16fe7564121564c1844935592dc3315c73d1f78f7c908a4338b1d783618811e694c9bb6d5f9233e58d languageName: node linkType: hard -"@babel/plugin-transform-reserved-words@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-reserved-words@npm:7.24.1" +"@babel/plugin-transform-reserved-words@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-reserved-words@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/936d6e73cafb2cbb495f6817c6f8463288dbc9ab3c44684b931ebc1ece24f0d55dfabc1a75ba1de5b48843d0fef448dcfdbecb8485e4014f8f41d0d1440c536f + checksum: 10c0/5d2d4c579bd90c60fc6468a1285b3384e7b650b47d41a937a1590d4aecfc28bd945e82704c6e71cc91aa016b7e78c5594290c1c386edf11ec98e09e36235c5ae languageName: node linkType: hard "@babel/plugin-transform-runtime@npm:^7.22.4": - version: 7.24.3 - resolution: "@babel/plugin-transform-runtime@npm:7.24.3" + version: 7.24.6 + resolution: "@babel/plugin-transform-runtime@npm:7.24.6" dependencies: - "@babel/helper-module-imports": "npm:^7.24.3" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-module-imports": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" babel-plugin-polyfill-corejs2: "npm:^0.4.10" babel-plugin-polyfill-corejs3: "npm:^0.10.1" babel-plugin-polyfill-regenerator: "npm:^0.6.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/ee01967bf405d84bd95ca4089166a18fb23fe9851a6da53dcf712a7f8ba003319996f21f320d568ec76126e18adfaee978206ccda86eef7652d47cc9a052e75e + checksum: 10c0/89c43c1236506ecbfc547b12936283ca41e611430c2d2e6d12bf1cbdb0d80760cdae481951f486946733e1c9ae064cb05f4bc779c65b3288d40963b0c4a20c5c languageName: node linkType: hard -"@babel/plugin-transform-shorthand-properties@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.1" +"@babel/plugin-transform-shorthand-properties@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/8273347621183aada3cf1f3019d8d5f29467ba13a75b72cb405bc7f23b7e05fd85f4edb1e4d9f0103153dddb61826a42dc24d466480d707f8932c1923a4c25fa + checksum: 10c0/4141b5da1d0d20d66ca0affaef8dfc45ed5e954bfa9003eb8aa779842599de443b37c2b265da27693f304c35ab68a682b44098e9eea0d39f8f94072ab616657f languageName: node linkType: hard -"@babel/plugin-transform-spread@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-spread@npm:7.24.1" +"@babel/plugin-transform-spread@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-spread@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/50a0302e344546d57e5c9f4dea575f88e084352eeac4e9a3e238c41739eef2df1daf4a7ebbb3ccb7acd3447f6a5ce9938405f98bf5f5583deceb8257f5a673c9 + checksum: 10c0/6d12da05311690c4a73d775688ba6931b441e96e512377a166a60184292edeac0b17f5154a49e2f1d262a3f80b96e064bc9c88c63b2a6125f0a2132eff9ed585 languageName: node linkType: hard -"@babel/plugin-transform-sticky-regex@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.1" +"@babel/plugin-transform-sticky-regex@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/786fe2ae11ef9046b9fa95677935abe495031eebf1274ad03f2054a20adea7b9dbd00336ac0b143f7924bc562e5e09793f6e8613607674b97e067d4838ccc4a0 + checksum: 10c0/2a65f57554f51d3b9cd035513a610f47e46b26dba112b3b9fb42d1c1f2ae153fce8f76294b4721d099817814f57895c656f5b7dccd5df683277da6522c817ee9 languageName: node linkType: hard -"@babel/plugin-transform-template-literals@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-template-literals@npm:7.24.1" +"@babel/plugin-transform-template-literals@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-template-literals@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/f73bcda5488eb81c6e7a876498d9e6b72be32fca5a4d9db9053491a2d1300cd27b889b463fd2558f3cd5826a85ed00f61d81b234aa55cb5a0abf1b6fa1bd5026 + checksum: 10c0/fcde48e9c3ecd7f5f37ceb6908f1edd537d3115fc2f27d187d58fd83b2a13637a1bb3d24589d841529ed081405b951bf1c5d194ea81eff6ad2d88204d153010d languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.5" +"@babel/plugin-transform-typeof-symbol@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.5" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/5f0b5e33a86b84d89673829ffa2b5f175e102d3d0f45917cda121bc2b3650e1e5bb7a653f8cc1059c5b3a7b2e91e1aafd6623028b96ae752715cc5c2171c96e5 + checksum: 10c0/a24b3a3c7b87c6496ee13d2438effd4645868f054397357ec3cbe92a2f0df4152ac7fd7228cb956576c1b772c0675b065d6ad5f5053c382e97dd022015e9a028 languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-typescript@npm:7.24.1" +"@babel/plugin-transform-typescript@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-typescript@npm:7.24.6" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-create-class-features-plugin": "npm:^7.24.1" - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/plugin-syntax-typescript": "npm:^7.24.1" + "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-create-class-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/plugin-syntax-typescript": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/9abce423ed2d3cb9398b09e3ed9efea661e92bd32e919f5c7942ac4bad4c5fd23a1d575bb7444d8c92261b68fb626552e0d9eea960372b6b6f54c2c9699a2649 + checksum: 10c0/46b054e4d4253187403e392ef30f4dd624d8486a1992703f5ff1b415d4e8d00f474e35fb77bc7a3a16a17330873cadcd5af4a8493c61b16da2dde212b2788ccd languageName: node linkType: hard -"@babel/plugin-transform-unicode-escapes@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.1" +"@babel/plugin-transform-unicode-escapes@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/67a72a1ed99639de6a93aead35b1993cb3f0eb178a8991fcef48732c38c9f0279c85bbe1e2e2477b85afea873e738ff0955a35057635ce67bc149038e2d8a28e + checksum: 10c0/0e4038c589b7a63a2469466a25b78aad4ecb7267732e3c953c3055f9a77c7bee859a71983a08b025179f1b094964f2ebbfca1b6c33de4ead90a0b5ef06ddb47e languageName: node linkType: hard -"@babel/plugin-transform-unicode-property-regex@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.1" +"@babel/plugin-transform-unicode-property-regex@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.6" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d9d9752df7d51bf9357c0bf3762fe16b8c841fca9ecf4409a16f15ccc34be06e8e71abfaee1251b7d451227e70e6b873b36f86b090efdb20f6f7de5fdb6c7a05 + checksum: 10c0/bca99e00de91d0460dfcb25f285f3606248acc905193c05587e2862c54ddb790c5d8cb45e80927290390cffbcba7620f8af3e74c5301ff0c1c59ce7d47c5629f languageName: node linkType: hard -"@babel/plugin-transform-unicode-regex@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.1" +"@babel/plugin-transform-unicode-regex@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.6" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6046ab38e5d14ed97dbb921bd79ac1d7ad9d3286da44a48930e980b16896db2df21e093563ec3c916a630dc346639bf47c5924a33902a06fe3bbb5cdc7ef5f2f + checksum: 10c0/ab6e253cfc38c7e8a2844d7ad46f85fdcbe33610b7f92f71045cf0b040438a08f1f1717ab4b84c480537f54e5478db8b404a4ccc2ff846b4e3ed33d373e3b47a languageName: node linkType: hard -"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.1": - version: 7.24.1 - resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.24.1" +"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.24.6" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/b6c1f6b90afeeddf97e5713f72575787fcb7179be7b4c961869bfbc66915f66540dc49da93e4369da15596bd44b896d1eb8a50f5e1fd907abd7a1a625901006b + checksum: 10c0/a52e84f85519fed330e88f7a17611064d2b5f1d0fe2823f8113ed312828e69787888bd023f404e8d35d0bb96461e42e19cdc4f0a44d35959bc86c219a3062237 languageName: node linkType: hard "@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4": - version: 7.24.5 - resolution: "@babel/preset-env@npm:7.24.5" + version: 7.24.6 + resolution: "@babel/preset-env@npm:7.24.6" dependencies: - "@babel/compat-data": "npm:^7.24.4" - "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-plugin-utils": "npm:^7.24.5" - "@babel/helper-validator-option": "npm:^7.23.5" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.5" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.1" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.1" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.1" + "@babel/compat-data": "npm:^7.24.6" + "@babel/helper-compilation-targets": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-validator-option": "npm:^7.24.6" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.6" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.6" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.6" "@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators": "npm:^7.8.4" "@babel/plugin-syntax-class-properties": "npm:^7.12.13" "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" - "@babel/plugin-syntax-import-assertions": "npm:^7.24.1" - "@babel/plugin-syntax-import-attributes": "npm:^7.24.1" + "@babel/plugin-syntax-import-assertions": "npm:^7.24.6" + "@babel/plugin-syntax-import-attributes": "npm:^7.24.6" "@babel/plugin-syntax-import-meta": "npm:^7.10.4" "@babel/plugin-syntax-json-strings": "npm:^7.8.3" "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" @@ -1375,54 +1374,54 @@ __metadata: "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" - "@babel/plugin-transform-arrow-functions": "npm:^7.24.1" - "@babel/plugin-transform-async-generator-functions": "npm:^7.24.3" - "@babel/plugin-transform-async-to-generator": "npm:^7.24.1" - "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.1" - "@babel/plugin-transform-block-scoping": "npm:^7.24.5" - "@babel/plugin-transform-class-properties": "npm:^7.24.1" - "@babel/plugin-transform-class-static-block": "npm:^7.24.4" - "@babel/plugin-transform-classes": "npm:^7.24.5" - "@babel/plugin-transform-computed-properties": "npm:^7.24.1" - "@babel/plugin-transform-destructuring": "npm:^7.24.5" - "@babel/plugin-transform-dotall-regex": "npm:^7.24.1" - "@babel/plugin-transform-duplicate-keys": "npm:^7.24.1" - "@babel/plugin-transform-dynamic-import": "npm:^7.24.1" - "@babel/plugin-transform-exponentiation-operator": "npm:^7.24.1" - "@babel/plugin-transform-export-namespace-from": "npm:^7.24.1" - "@babel/plugin-transform-for-of": "npm:^7.24.1" - "@babel/plugin-transform-function-name": "npm:^7.24.1" - "@babel/plugin-transform-json-strings": "npm:^7.24.1" - "@babel/plugin-transform-literals": "npm:^7.24.1" - "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.1" - "@babel/plugin-transform-member-expression-literals": "npm:^7.24.1" - "@babel/plugin-transform-modules-amd": "npm:^7.24.1" - "@babel/plugin-transform-modules-commonjs": "npm:^7.24.1" - "@babel/plugin-transform-modules-systemjs": "npm:^7.24.1" - "@babel/plugin-transform-modules-umd": "npm:^7.24.1" - "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.22.5" - "@babel/plugin-transform-new-target": "npm:^7.24.1" - "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.1" - "@babel/plugin-transform-numeric-separator": "npm:^7.24.1" - "@babel/plugin-transform-object-rest-spread": "npm:^7.24.5" - "@babel/plugin-transform-object-super": "npm:^7.24.1" - "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.1" - "@babel/plugin-transform-optional-chaining": "npm:^7.24.5" - "@babel/plugin-transform-parameters": "npm:^7.24.5" - "@babel/plugin-transform-private-methods": "npm:^7.24.1" - "@babel/plugin-transform-private-property-in-object": "npm:^7.24.5" - "@babel/plugin-transform-property-literals": "npm:^7.24.1" - "@babel/plugin-transform-regenerator": "npm:^7.24.1" - "@babel/plugin-transform-reserved-words": "npm:^7.24.1" - "@babel/plugin-transform-shorthand-properties": "npm:^7.24.1" - "@babel/plugin-transform-spread": "npm:^7.24.1" - "@babel/plugin-transform-sticky-regex": "npm:^7.24.1" - "@babel/plugin-transform-template-literals": "npm:^7.24.1" - "@babel/plugin-transform-typeof-symbol": "npm:^7.24.5" - "@babel/plugin-transform-unicode-escapes": "npm:^7.24.1" - "@babel/plugin-transform-unicode-property-regex": "npm:^7.24.1" - "@babel/plugin-transform-unicode-regex": "npm:^7.24.1" - "@babel/plugin-transform-unicode-sets-regex": "npm:^7.24.1" + "@babel/plugin-transform-arrow-functions": "npm:^7.24.6" + "@babel/plugin-transform-async-generator-functions": "npm:^7.24.6" + "@babel/plugin-transform-async-to-generator": "npm:^7.24.6" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.6" + "@babel/plugin-transform-block-scoping": "npm:^7.24.6" + "@babel/plugin-transform-class-properties": "npm:^7.24.6" + "@babel/plugin-transform-class-static-block": "npm:^7.24.6" + "@babel/plugin-transform-classes": "npm:^7.24.6" + "@babel/plugin-transform-computed-properties": "npm:^7.24.6" + "@babel/plugin-transform-destructuring": "npm:^7.24.6" + "@babel/plugin-transform-dotall-regex": "npm:^7.24.6" + "@babel/plugin-transform-duplicate-keys": "npm:^7.24.6" + "@babel/plugin-transform-dynamic-import": "npm:^7.24.6" + "@babel/plugin-transform-exponentiation-operator": "npm:^7.24.6" + "@babel/plugin-transform-export-namespace-from": "npm:^7.24.6" + "@babel/plugin-transform-for-of": "npm:^7.24.6" + "@babel/plugin-transform-function-name": "npm:^7.24.6" + "@babel/plugin-transform-json-strings": "npm:^7.24.6" + "@babel/plugin-transform-literals": "npm:^7.24.6" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.6" + "@babel/plugin-transform-member-expression-literals": "npm:^7.24.6" + "@babel/plugin-transform-modules-amd": "npm:^7.24.6" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.6" + "@babel/plugin-transform-modules-systemjs": "npm:^7.24.6" + "@babel/plugin-transform-modules-umd": "npm:^7.24.6" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.6" + "@babel/plugin-transform-new-target": "npm:^7.24.6" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.6" + "@babel/plugin-transform-numeric-separator": "npm:^7.24.6" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.6" + "@babel/plugin-transform-object-super": "npm:^7.24.6" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.6" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.6" + "@babel/plugin-transform-parameters": "npm:^7.24.6" + "@babel/plugin-transform-private-methods": "npm:^7.24.6" + "@babel/plugin-transform-private-property-in-object": "npm:^7.24.6" + "@babel/plugin-transform-property-literals": "npm:^7.24.6" + "@babel/plugin-transform-regenerator": "npm:^7.24.6" + "@babel/plugin-transform-reserved-words": "npm:^7.24.6" + "@babel/plugin-transform-shorthand-properties": "npm:^7.24.6" + "@babel/plugin-transform-spread": "npm:^7.24.6" + "@babel/plugin-transform-sticky-regex": "npm:^7.24.6" + "@babel/plugin-transform-template-literals": "npm:^7.24.6" + "@babel/plugin-transform-typeof-symbol": "npm:^7.24.6" + "@babel/plugin-transform-unicode-escapes": "npm:^7.24.6" + "@babel/plugin-transform-unicode-property-regex": "npm:^7.24.6" + "@babel/plugin-transform-unicode-regex": "npm:^7.24.6" + "@babel/plugin-transform-unicode-sets-regex": "npm:^7.24.6" "@babel/preset-modules": "npm:0.1.6-no-external-plugins" babel-plugin-polyfill-corejs2: "npm:^0.4.10" babel-plugin-polyfill-corejs3: "npm:^0.10.4" @@ -1431,7 +1430,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/2cc0edae09205d6409a75d02e53aaa1c590e89adbb7b389019c7b75e4c47b6b63eeb1a816df5c42b672ce410747e7ddc23b6747e8e41a6c95d6fa00c665509e2 + checksum: 10c0/d837d294197803d550e48d9458a356853a54a0528e7cdc51c2b8a5d8dfe41c6fbc597b4fc67464615a7385198a3db2e839da15cca7b9502fedf27170fc6ef673 languageName: node linkType: hard @@ -1449,33 +1448,33 @@ __metadata: linkType: hard "@babel/preset-react@npm:^7.12.5, @babel/preset-react@npm:^7.22.3": - version: 7.24.1 - resolution: "@babel/preset-react@npm:7.24.1" + version: 7.24.6 + resolution: "@babel/preset-react@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-validator-option": "npm:^7.23.5" - "@babel/plugin-transform-react-display-name": "npm:^7.24.1" - "@babel/plugin-transform-react-jsx": "npm:^7.23.4" - "@babel/plugin-transform-react-jsx-development": "npm:^7.22.5" - "@babel/plugin-transform-react-pure-annotations": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-validator-option": "npm:^7.24.6" + "@babel/plugin-transform-react-display-name": "npm:^7.24.6" + "@babel/plugin-transform-react-jsx": "npm:^7.24.6" + "@babel/plugin-transform-react-jsx-development": "npm:^7.24.6" + "@babel/plugin-transform-react-pure-annotations": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/a842abc5a024ed68a0ce4c1244607d40165cb6f8cf1817ebda282e470f20302d81c6a61cb41c1a31aa6c4e99ce93df4dd9e998a8ded1417c25d7480f0e14103a + checksum: 10c0/edc470b86dfcfdedf53feca3f2266bd7f836a300806938a422f4120d39bbdea6a780b9b0a9ac0333e0bb1b8e554699a74cafd135b2a75b02b77ef1b21f7c7f62 languageName: node linkType: hard "@babel/preset-typescript@npm:^7.21.5": - version: 7.24.1 - resolution: "@babel/preset-typescript@npm:7.24.1" + version: 7.24.6 + resolution: "@babel/preset-typescript@npm:7.24.6" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/helper-validator-option": "npm:^7.23.5" - "@babel/plugin-syntax-jsx": "npm:^7.24.1" - "@babel/plugin-transform-modules-commonjs": "npm:^7.24.1" - "@babel/plugin-transform-typescript": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-validator-option": "npm:^7.24.6" + "@babel/plugin-syntax-jsx": "npm:^7.24.6" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.6" + "@babel/plugin-transform-typescript": "npm:^7.24.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/0033dc6fbc898ed0d8017c83a2dd5e095c82909e2f83e48cf9f305e3e9287148758c179ad90f27912cf98ca68bfec3643c57c70c0ca34d3a6c50dc8243aef406 + checksum: 10c0/bfcef91ed80d67301301e17a799814457b57bfd0d85d9897dce6df6ed0b0af155c0f5b2af7a1a122a3f36faaaa1de87ccf9954ce06d2f440898ffdfaf18aab86 languageName: node linkType: hard @@ -1496,51 +1495,51 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.24.5 - resolution: "@babel/runtime@npm:7.24.5" + version: 7.24.6 + resolution: "@babel/runtime@npm:7.24.6" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/05730e43e8ba6550eae9fd4fb5e7d9d3cb91140379425abcb2a1ff9cebad518a280d82c4c4b0f57ada26a863106ac54a748d90c775790c0e2cd0ddd85ccdf346 + checksum: 10c0/224ad205de33ea28979baaec89eea4c4d4e9482000dd87d15b97859365511cdd4d06517712504024f5d33a5fb9412f9b91c96f1d923974adf9359e1575cde049 languageName: node linkType: hard -"@babel/template@npm:^7.22.15, @babel/template@npm:^7.24.0, @babel/template@npm:^7.3.3": - version: 7.24.0 - resolution: "@babel/template@npm:7.24.0" +"@babel/template@npm:^7.24.6, @babel/template@npm:^7.3.3": + version: 7.24.6 + resolution: "@babel/template@npm:7.24.6" dependencies: - "@babel/code-frame": "npm:^7.23.5" - "@babel/parser": "npm:^7.24.0" - "@babel/types": "npm:^7.24.0" - checksum: 10c0/9d3dd8d22fe1c36bc3bdef6118af1f4b030aaf6d7d2619f5da203efa818a2185d717523486c111de8d99a8649ddf4bbf6b2a7a64962d8411cf6a8fa89f010e54 + "@babel/code-frame": "npm:^7.24.6" + "@babel/parser": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" + checksum: 10c0/a4d5805770de908b445f7cdcebfcb6eaa07b1ec9c7b78fd3f375a911b1522c249bddae6b96bc4aac24247cc603e3e6cffcf2fe50b4c929dfeb22de289b517525 languageName: node linkType: hard -"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/traverse@npm:7.24.5" +"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.6": + version: 7.24.6 + resolution: "@babel/traverse@npm:7.24.6" dependencies: - "@babel/code-frame": "npm:^7.24.2" - "@babel/generator": "npm:^7.24.5" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-hoist-variables": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.24.5" - "@babel/parser": "npm:^7.24.5" - "@babel/types": "npm:^7.24.5" + "@babel/code-frame": "npm:^7.24.6" + "@babel/generator": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.6" + "@babel/helper-function-name": "npm:^7.24.6" + "@babel/helper-hoist-variables": "npm:^7.24.6" + "@babel/helper-split-export-declaration": "npm:^7.24.6" + "@babel/parser": "npm:^7.24.6" + "@babel/types": "npm:^7.24.6" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10c0/3f22534bc2b2ed9208e55ef48af3b32939032b23cb9dc4037447cb108640df70bbb0b9fea86e9c58648949fdc2cb14e89aa79ffa3c62a5dd43459a52fe8c01d1 + checksum: 10c0/39027d5fc7a241c6b71bb5872c2bdcec53743cd7ef3c151bbe6fd7cf874d15f4bc09e5d7e19e2f534b0eb2c115f5368553885fa4253aa1bc9441c6e5bf9efdaf languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.24.5 - resolution: "@babel/types@npm:7.24.5" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.6, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.24.6 + resolution: "@babel/types@npm:7.24.6" dependencies: - "@babel/helper-string-parser": "npm:^7.24.1" - "@babel/helper-validator-identifier": "npm:^7.24.5" + "@babel/helper-string-parser": "npm:^7.24.6" + "@babel/helper-validator-identifier": "npm:^7.24.6" to-fast-properties: "npm:^2.0.0" - checksum: 10c0/e1284eb046c5e0451b80220d1200e2327e0a8544a2fe45bb62c952e5fdef7099c603d2336b17b6eac3cc046b7a69bfbce67fe56e1c0ea48cd37c65cb88638f2a + checksum: 10c0/1d94d92d97ef49030ad7f9e14cfccfeb70b1706dabcaa69037e659ec9d2c3178fb005d2088cce40d88dfc1306153d9157fe038a79ea2be92e5e6b99a59ef80cc languageName: node linkType: hard From e947f1f2ed005ec764a1ddbc53965cece533a62f Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 24 May 2024 10:25:42 +0200 Subject: [PATCH 242/658] [Glitch] Fix a leftover argument to `api()` Port 8ea2726376ed9507072a8e2ec07fdfc219264dad to glitch-soc Signed-off-by: Claire --- .../hashtag_timeline/containers/column_settings_container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js b/app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js index be95004cc7..680b44519b 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/containers/column_settings_container.js @@ -15,7 +15,7 @@ const mapStateToProps = (state, { columnId }) => { return { settings: columns.get(index).get('params'), onLoad (value) { - return api(() => state).get('/api/v2/search', { params: { q: value, type: 'hashtags' } }).then(response => { + return api().get('/api/v2/search', { params: { q: value, type: 'hashtags' } }).then(response => { return (response.data.hashtags || []).map((tag) => { return { value: tag.name, label: `#${tag.name}` }; }); From 1a2a28eb4af996b6277de11da7b217de903ab508 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 24 May 2024 17:13:34 +0200 Subject: [PATCH 243/658] Fix rubocop warnings --- app/lib/advanced_text_formatter.rb | 2 +- config/initializers/0_duplicate_migrations.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/advanced_text_formatter.rb b/app/lib/advanced_text_formatter.rb index cdf1e2d9cd..3ba4c92be3 100644 --- a/app/lib/advanced_text_formatter.rb +++ b/app/lib/advanced_text_formatter.rb @@ -31,7 +31,7 @@ class AdvancedTextFormatter < TextFormatter # @option options [String] :content_type def initialize(text, options = {}) @content_type = options.delete(:content_type) - super(text, options) + super @text = format_markdown(text) if content_type == 'text/markdown' end diff --git a/config/initializers/0_duplicate_migrations.rb b/config/initializers/0_duplicate_migrations.rb index ab50e5e900..f993571877 100644 --- a/config/initializers/0_duplicate_migrations.rb +++ b/config/initializers/0_duplicate_migrations.rb @@ -38,7 +38,7 @@ module ActiveRecord end end - super(direction, migrations, schema_migration, internal_metadata, target_version) + super end end From a5c808e9b033eeb605dcf6b36dc14ddb1127db7b Mon Sep 17 00:00:00 2001 From: Julius Rajala Date: Fri, 24 May 2024 19:39:03 +0300 Subject: [PATCH 244/658] Fix issue with post-create scripts failing on local docker (#28402) --- .devcontainer/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 97331f74ea..5d9917b399 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -2,6 +2,7 @@ version: '3' services: app: + working_dir: /workspaces/mastodon/ build: context: . dockerfile: Dockerfile From 6a75e1c8c82a1625867ea69be3d0c55697448f4e Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 27 May 2024 11:00:40 +0200 Subject: [PATCH 245/658] Fix `createDataLoadingThunk` to allow actions without arguments (#30439) --- .../mastodon/store/typed_functions.ts | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/app/javascript/mastodon/store/typed_functions.ts b/app/javascript/mastodon/store/typed_functions.ts index 0392f373c0..dae37e6225 100644 --- a/app/javascript/mastodon/store/typed_functions.ts +++ b/app/javascript/mastodon/store/typed_functions.ts @@ -89,21 +89,17 @@ type OnData = ( }, ) => ReturnedData | DiscardLoadData | Promise; +type ArgsType = Record | undefined; + // Overload when there is no `onData` method, the payload is the `onData` result -export function createDataLoadingThunk< - LoadDataResult, - Args extends Record, ->( +export function createDataLoadingThunk( name: string, loadData: (args: Args) => Promise, thunkOptions?: AppThunkOptions, ): ReturnType>; // Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty -export function createDataLoadingThunk< - LoadDataResult, - Args extends Record, ->( +export function createDataLoadingThunk( name: string, loadData: (args: Args) => Promise, onDataOrThunkOptions?: @@ -113,10 +109,7 @@ export function createDataLoadingThunk< ): ReturnType>; // Overload when the `onData` method returns nothing, then the mayload is the `onData` result -export function createDataLoadingThunk< - LoadDataResult, - Args extends Record, ->( +export function createDataLoadingThunk( name: string, loadData: (args: Args) => Promise, onDataOrThunkOptions?: AppThunkOptions | OnData, @@ -126,7 +119,7 @@ export function createDataLoadingThunk< // Overload when there is an `onData` method returning something export function createDataLoadingThunk< LoadDataResult, - Args extends Record, + Args extends ArgsType, Returned, >( name: string, @@ -162,7 +155,7 @@ export function createDataLoadingThunk< */ export function createDataLoadingThunk< LoadDataResult, - Args extends Record, + Args extends ArgsType, Returned, >( name: string, From 404e203d41bc47e78a2265368b6caaad084dbb16 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 11:19:44 +0200 Subject: [PATCH 246/658] chore(deps): update dependency simple_form to v5.3.1 (#30416) 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 5feab4d095..934d41334d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -425,7 +425,7 @@ GEM mime-types-data (3.2024.0507) mini_mime (1.1.5) mini_portile2 (2.8.6) - minitest (5.23.0) + minitest (5.23.1) msgpack (1.7.2) multi_json (1.15.0) multipart-post (2.4.0) @@ -799,7 +799,7 @@ GEM thor (>= 0.20, < 3.0) simple-navigation (4.4.0) activesupport (>= 2.3.2) - simple_form (5.3.0) + simple_form (5.3.1) actionpack (>= 5.2) activemodel (>= 5.2) simplecov (0.22.0) From 564ebfefcf1deb79b38422dfadbc9d5023eca4b6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 27 May 2024 05:20:28 -0400 Subject: [PATCH 247/658] Remove hard reference from status pin validator spec (#30432) --- spec/validators/status_pin_validator_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/validators/status_pin_validator_spec.rb b/spec/validators/status_pin_validator_spec.rb index d5109f990f..e50a952db8 100644 --- a/spec/validators/status_pin_validator_spec.rb +++ b/spec/validators/status_pin_validator_spec.rb @@ -45,8 +45,8 @@ RSpec.describe StatusPinValidator do end end - context 'when pin.account.status_pins.count > 4 && pin.account.local?' do - let(:count) { 5 } + context 'when pin account is local and has too many pins' do + let(:count) { described_class::PIN_LIMIT + 1 } let(:local) { true } it 'calls errors.add' do From 3750e8050cb4a5707e76dfb8f49687cc0984f67f Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 27 May 2024 11:24:59 +0200 Subject: [PATCH 248/658] Enable stricter Typescript options (#30435) --- app/javascript/entrypoints/public.tsx | 12 ++++++------ .../entrypoints/remote_interaction_helper.ts | 9 ++++++++- .../mastodon/components/animated_number.tsx | 5 +++-- app/javascript/mastodon/components/hashtag_bar.tsx | 7 +++++-- app/javascript/mastodon/components/short_number.tsx | 2 +- .../mastodon/features/emoji/emoji_mart_data_light.ts | 5 ++++- .../features/emoji/emoji_unicode_mapping_light.ts | 5 ++++- app/javascript/mastodon/store/middlewares/sounds.ts | 5 +++-- tsconfig.json | 2 ++ 9 files changed, 36 insertions(+), 16 deletions(-) diff --git a/app/javascript/entrypoints/public.tsx b/app/javascript/entrypoints/public.tsx index d45927226c..40a9b7c0ca 100644 --- a/app/javascript/entrypoints/public.tsx +++ b/app/javascript/entrypoints/public.tsx @@ -65,7 +65,7 @@ window.addEventListener('message', (e) => { { type: 'setHeight', id: data.id, - height: document.getElementsByTagName('html')[0].scrollHeight, + height: document.getElementsByTagName('html')[0]?.scrollHeight, }, '*', ); @@ -135,7 +135,7 @@ function loaded() { ); }; const todayFormat = new IntlMessageFormat( - localeData['relative_format.today'] || 'Today at {time}', + localeData['relative_format.today'] ?? 'Today at {time}', locale, ); @@ -288,13 +288,13 @@ function loaded() { if (statusEl.dataset.spoiler === 'expanded') { statusEl.dataset.spoiler = 'folded'; this.textContent = new IntlMessageFormat( - localeData['status.show_more'] || 'Show more', + localeData['status.show_more'] ?? 'Show more', locale, ).format() as string; } else { statusEl.dataset.spoiler = 'expanded'; this.textContent = new IntlMessageFormat( - localeData['status.show_less'] || 'Show less', + localeData['status.show_less'] ?? 'Show less', locale, ).format() as string; } @@ -316,8 +316,8 @@ function loaded() { const message = statusEl.dataset.spoiler === 'expanded' - ? localeData['status.show_less'] || 'Show less' - : localeData['status.show_more'] || 'Show more'; + ? localeData['status.show_less'] ?? 'Show less' + : localeData['status.show_more'] ?? 'Show more'; spoilerLink.textContent = new IntlMessageFormat( message, locale, diff --git a/app/javascript/entrypoints/remote_interaction_helper.ts b/app/javascript/entrypoints/remote_interaction_helper.ts index d5834c6c3d..419571c896 100644 --- a/app/javascript/entrypoints/remote_interaction_helper.ts +++ b/app/javascript/entrypoints/remote_interaction_helper.ts @@ -67,7 +67,9 @@ const fetchInteractionURLFailure = () => { ); }; -const isValidDomain = (value: string) => { +const isValidDomain = (value: unknown) => { + if (typeof value !== 'string') return false; + const url = new URL('https:///path'); url.hostname = value; return url.hostname === value; @@ -124,6 +126,11 @@ const fromAcct = (acct: string) => { const domain = segments[1]; const fallbackTemplate = `https://${domain}/authorize_interaction?uri={uri}`; + if (!domain) { + fetchInteractionURLFailure(); + return; + } + axios .get(`https://${domain}/.well-known/webfinger`, { params: { resource: `acct:${acct}` }, diff --git a/app/javascript/mastodon/components/animated_number.tsx b/app/javascript/mastodon/components/animated_number.tsx index e98e30b242..6c1e0aaec1 100644 --- a/app/javascript/mastodon/components/animated_number.tsx +++ b/app/javascript/mastodon/components/animated_number.tsx @@ -48,8 +48,9 @@ export const AnimatedNumber: React.FC = ({ value }) => { 0 ? 'absolute' : 'static', - transform: `translateY(${style.y * 100}%)`, + position: + direction * (style.y ?? 0) > 0 ? 'absolute' : 'static', + transform: `translateY(${(style.y ?? 0) * 100}%)`, }} > diff --git a/app/javascript/mastodon/components/hashtag_bar.tsx b/app/javascript/mastodon/components/hashtag_bar.tsx index ed5de7d3a5..1642ba6504 100644 --- a/app/javascript/mastodon/components/hashtag_bar.tsx +++ b/app/javascript/mastodon/components/hashtag_bar.tsx @@ -52,7 +52,10 @@ function uniqueHashtagsWithCaseHandling(hashtags: string[]) { ); return Object.values(groups).map((tags) => { - if (tags.length === 1) return tags[0]; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know that the array has at least one element + const firstTag = tags[0]!; + + if (tags.length === 1) return firstTag; // The best match is the one where we have the less difference between upper and lower case letter count const best = minBy(tags, (tag) => { @@ -66,7 +69,7 @@ function uniqueHashtagsWithCaseHandling(hashtags: string[]) { return Math.abs(lowerCase - upperCase); }); - return best ?? tags[0]; + return best ?? firstTag; }); } diff --git a/app/javascript/mastodon/components/short_number.tsx b/app/javascript/mastodon/components/short_number.tsx index 74c3c5d75e..a0b523aaad 100644 --- a/app/javascript/mastodon/components/short_number.tsx +++ b/app/javascript/mastodon/components/short_number.tsx @@ -48,7 +48,7 @@ const ShortNumberCounter: React.FC = ({ value }) => { const count = ( ); diff --git a/app/javascript/mastodon/features/emoji/emoji_mart_data_light.ts b/app/javascript/mastodon/features/emoji/emoji_mart_data_light.ts index ffca1f8b06..806a3f8927 100644 --- a/app/javascript/mastodon/features/emoji/emoji_mart_data_light.ts +++ b/app/javascript/mastodon/features/emoji/emoji_mart_data_light.ts @@ -29,7 +29,10 @@ const emojis: Emojis = {}; // decompress Object.keys(shortCodesToEmojiData).forEach((shortCode) => { - const [_filenameData, searchData] = shortCodesToEmojiData[shortCode]; + const emojiData = shortCodesToEmojiData[shortCode]; + if (!emojiData) return; + + const [_filenameData, searchData] = emojiData; const [native, short_names, search, unified] = searchData; emojis[shortCode] = { diff --git a/app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.ts b/app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.ts index 191419496f..d116c6c62c 100644 --- a/app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.ts +++ b/app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.ts @@ -46,7 +46,10 @@ function processEmojiMapData( Object.keys(shortCodesToEmojiData).forEach( (shortCode: ShortCodesToEmojiDataKey) => { if (shortCode === undefined) return; - const [filenameData, _searchData] = shortCodesToEmojiData[shortCode]; + + const emojiData = shortCodesToEmojiData[shortCode]; + if (!emojiData) return; + const [filenameData, _searchData] = emojiData; filenameData.forEach((emojiMapData) => { processEmojiMapData(emojiMapData, shortCode); }); diff --git a/app/javascript/mastodon/store/middlewares/sounds.ts b/app/javascript/mastodon/store/middlewares/sounds.ts index 720ee163e9..91407b1ec0 100644 --- a/app/javascript/mastodon/store/middlewares/sounds.ts +++ b/app/javascript/mastodon/store/middlewares/sounds.ts @@ -74,8 +74,9 @@ export const soundsMiddleware = (): Middleware< if (isActionWithMetaSound(action)) { const sound = action.meta.sound; - if (sound && Object.hasOwn(soundCache, sound)) { - play(soundCache[sound]); + if (sound) { + const s = soundCache[sound]; + if (s) play(s); } } diff --git a/tsconfig.json b/tsconfig.json index 7010dda1fc..cc1f18a992 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,8 @@ "allowJs": true, "noEmit": true, "strict": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": true, "esModuleInterop": true, "skipLibCheck": true, "baseUrl": "./", From 1034f13f57ec98f316e2b356957d01992371b59d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 11:25:55 +0200 Subject: [PATCH 249/658] chore(deps): update devdependencies (non-major) (#30442) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 256 ++++++++++++++++++++++++++---------------------------- 1 file changed, 121 insertions(+), 135 deletions(-) diff --git a/yarn.lock b/yarn.lock index 03157cce55..ad07e4e426 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1590,7 +1590,7 @@ __metadata: languageName: node linkType: hard -"@csstools/css-parser-algorithms@npm:^2.6.1, @csstools/css-parser-algorithms@npm:^2.6.3": +"@csstools/css-parser-algorithms@npm:^2.6.3": version: 2.6.3 resolution: "@csstools/css-parser-algorithms@npm:2.6.3" peerDependencies: @@ -1599,14 +1599,14 @@ __metadata: languageName: node linkType: hard -"@csstools/css-tokenizer@npm:^2.2.4, @csstools/css-tokenizer@npm:^2.3.1": +"@csstools/css-tokenizer@npm:^2.3.1": version: 2.3.1 resolution: "@csstools/css-tokenizer@npm:2.3.1" checksum: 10c0/fed6619fb5108e109d4dd10b0e967035a92793bae8fb84544e1342058b6df4e306d9d075623e2201fe88831b1ada797aea3546a8d12229d2d81cd7a5dfee4444 languageName: node linkType: hard -"@csstools/media-query-list-parser@npm:^2.1.11, @csstools/media-query-list-parser@npm:^2.1.9": +"@csstools/media-query-list-parser@npm:^2.1.11": version: 2.1.11 resolution: "@csstools/media-query-list-parser@npm:2.1.11" peerDependencies: @@ -1982,7 +1982,7 @@ __metadata: languageName: node linkType: hard -"@csstools/selector-specificity@npm:^3.0.3, @csstools/selector-specificity@npm:^3.1.1": +"@csstools/selector-specificity@npm:^3.1.1": version: 3.1.1 resolution: "@csstools/selector-specificity@npm:3.1.1" peerDependencies: @@ -2007,10 +2007,10 @@ __metadata: languageName: node linkType: hard -"@dual-bundle/import-meta-resolve@npm:^4.0.0": - version: 4.0.0 - resolution: "@dual-bundle/import-meta-resolve@npm:4.0.0" - checksum: 10c0/868b8314fc753b7767887108535afe3288de941d92bc8453164dbcb1abe886b171e338f6f7d02ff556256dee69c90e4ac6360e0c6a856a5ad7190274ab52de2e +"@dual-bundle/import-meta-resolve@npm:^4.1.0": + version: 4.1.0 + resolution: "@dual-bundle/import-meta-resolve@npm:4.1.0" + checksum: 10c0/55069e550ee2710e738dd8bbd34aba796cede456287454b50c3be46fbef8695d00625677f3f41f5ffbec1174c0f57f314da9a908388bc9f8ad41a8438db884d9 languageName: node linkType: hard @@ -5609,12 +5609,12 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.2, braces@npm:~3.0.2": - version: 3.0.2 - resolution: "braces@npm:3.0.2" +"braces@npm:^3.0.3, braces@npm:~3.0.2": + version: 3.0.3 + resolution: "braces@npm:3.0.3" dependencies: - fill-range: "npm:^7.0.1" - checksum: 10c0/321b4d675791479293264019156ca322163f02dc06e3c4cab33bb15cd43d80b51efef69b0930cfde3acd63d126ebca24cd0544fa6f261e093a0fb41ab9dda381 + fill-range: "npm:^7.1.1" + checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 languageName: node linkType: hard @@ -5917,13 +5917,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:5.3.0": - version: 5.3.0 - resolution: "chalk@npm:5.3.0" - checksum: 10c0/8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09 - languageName: node - linkType: hard - "chalk@npm:^2.4.1, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" @@ -5955,6 +5948,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:~5.3.0": + version: 5.3.0 + resolution: "chalk@npm:5.3.0" + checksum: 10c0/8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09 + languageName: node + linkType: hard + "char-regex@npm:^1.0.2": version: 1.0.2 resolution: "char-regex@npm:1.0.2" @@ -6247,13 +6247,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:11.1.0": - version: 11.1.0 - resolution: "commander@npm:11.1.0" - checksum: 10c0/13cc6ac875e48780250f723fb81c1c1178d35c5decb1abb1b628b3177af08a8554e76b2c0f29de72d69eef7c864d12613272a71fabef8047922bc622ab75a179 - languageName: node - linkType: hard - "commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -6268,6 +6261,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:~12.1.0": + version: 12.1.0 + resolution: "commander@npm:12.1.0" + checksum: 10c0/6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9 + languageName: node + linkType: hard + "comment-parser@npm:1.4.1": version: 1.4.1 resolution: "comment-parser@npm:1.4.1" @@ -6947,7 +6947,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:~4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -8165,23 +8165,6 @@ __metadata: languageName: node linkType: hard -"execa@npm:8.0.1": - version: 8.0.1 - resolution: "execa@npm:8.0.1" - dependencies: - cross-spawn: "npm:^7.0.3" - get-stream: "npm:^8.0.1" - human-signals: "npm:^5.0.0" - is-stream: "npm:^3.0.0" - merge-stream: "npm:^2.0.0" - npm-run-path: "npm:^5.1.0" - onetime: "npm:^6.0.0" - signal-exit: "npm:^4.1.0" - strip-final-newline: "npm:^3.0.0" - checksum: 10c0/2c52d8775f5bf103ce8eec9c7ab3059909ba350a5164744e9947ed14a53f51687c040a250bda833f906d1283aa8803975b84e6c8f7a7c42f99dc8ef80250d1af - languageName: node - linkType: hard - "execa@npm:^1.0.0": version: 1.0.0 resolution: "execa@npm:1.0.0" @@ -8214,6 +8197,23 @@ __metadata: languageName: node linkType: hard +"execa@npm:~8.0.1": + version: 8.0.1 + resolution: "execa@npm:8.0.1" + dependencies: + cross-spawn: "npm:^7.0.3" + get-stream: "npm:^8.0.1" + human-signals: "npm:^5.0.0" + is-stream: "npm:^3.0.0" + merge-stream: "npm:^2.0.0" + npm-run-path: "npm:^5.1.0" + onetime: "npm:^6.0.0" + signal-exit: "npm:^4.1.0" + strip-final-newline: "npm:^3.0.0" + checksum: 10c0/2c52d8775f5bf103ce8eec9c7ab3059909ba350a5164744e9947ed14a53f51687c040a250bda833f906d1283aa8803975b84e6c8f7a7c42f99dc8ef80250d1af + languageName: node + linkType: hard + "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" @@ -8339,10 +8339,10 @@ __metadata: languageName: node linkType: hard -"fast-copy@npm:^3.0.0": - version: 3.0.1 - resolution: "fast-copy@npm:3.0.1" - checksum: 10c0/a8310dbcc4c94ed001dc3e0bbc3c3f0491bb04e6c17163abe441a54997ba06cdf1eb532c2f05e54777c6f072c84548c23ef0ecd54665cd611be1d42f37eca258 +"fast-copy@npm:^3.0.2": + version: 3.0.2 + resolution: "fast-copy@npm:3.0.2" + checksum: 10c0/02e8b9fd03c8c024d2987760ce126456a0e17470850b51e11a1c3254eed6832e4733ded2d93316c82bc0b36aeb991ad1ff48d1ba95effe7add7c3ab8d8eb554a languageName: node linkType: hard @@ -8493,12 +8493,12 @@ __metadata: languageName: node linkType: hard -"fill-range@npm:^7.0.1": - version: 7.0.1 - resolution: "fill-range@npm:7.0.1" +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" dependencies: to-regex-range: "npm:^5.0.1" - checksum: 10c0/7cdad7d426ffbaadf45aeb5d15ec675bbd77f7597ad5399e3d2766987ed20bda24d5fac64b3ee79d93276f5865608bb22344a26b9b1ae6c4d00bd94bf611623f + checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 languageName: node linkType: hard @@ -11229,10 +11229,10 @@ __metadata: languageName: node linkType: hard -"known-css-properties@npm:^0.30.0": - version: 0.30.0 - resolution: "known-css-properties@npm:0.30.0" - checksum: 10c0/8b487a6b33487affcec41eb392ceb77acf4d093558dde5c88b5ea06b9a3c81781876d7cb09872e0518b9602f27c8f4112c9ac333e02c90a91c8fbd12e202ed48 +"known-css-properties@npm:^0.31.0": + version: 0.31.0 + resolution: "known-css-properties@npm:0.31.0" + checksum: 10c0/8e643cbed32d7733278ba215c43dfc38fc7e77d391f66b81f07228af97d69ce2cebba03a9bc1ac859479e162aea812e258b30f4c93cb7b7adfd0622a141d36da languageName: node linkType: hard @@ -11269,14 +11269,7 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:3.0.0": - version: 3.0.0 - resolution: "lilconfig@npm:3.0.0" - checksum: 10c0/7f5ee7a658dc016cacf146815e8d88b06f06f4402823b8b0934e305a57a197f55ccc9c5cd4fb5ea1b2b821c8ccaf2d54abd59602a4931af06eabda332388d3e6 - languageName: node - linkType: hard - -"lilconfig@npm:^3.1.1": +"lilconfig@npm:^3.1.1, lilconfig@npm:~3.1.1": version: 3.1.1 resolution: "lilconfig@npm:3.1.1" checksum: 10c0/311b559794546894e3fe176663427326026c1c644145be9e8041c58e268aa9328799b8dfe7e4dd8c6a4ae305feae95a1c9e007db3569f35b42b6e1bc8274754c @@ -11291,36 +11284,36 @@ __metadata: linkType: hard "lint-staged@npm:^15.0.0": - version: 15.2.2 - resolution: "lint-staged@npm:15.2.2" + version: 15.2.5 + resolution: "lint-staged@npm:15.2.5" dependencies: - chalk: "npm:5.3.0" - commander: "npm:11.1.0" - debug: "npm:4.3.4" - execa: "npm:8.0.1" - lilconfig: "npm:3.0.0" - listr2: "npm:8.0.1" - micromatch: "npm:4.0.5" - pidtree: "npm:0.6.0" - string-argv: "npm:0.3.2" - yaml: "npm:2.3.4" + chalk: "npm:~5.3.0" + commander: "npm:~12.1.0" + debug: "npm:~4.3.4" + execa: "npm:~8.0.1" + lilconfig: "npm:~3.1.1" + listr2: "npm:~8.2.1" + micromatch: "npm:~4.0.7" + pidtree: "npm:~0.6.0" + string-argv: "npm:~0.3.2" + yaml: "npm:~2.4.2" bin: lint-staged: bin/lint-staged.js - checksum: 10c0/a1ba6c7ee53e30a0f6ea9a351d95d3d0d2be916a41b561e22907e9ea513eb18cb3dbe65bff3ec13fad15777999efe56b2e2a95427e31d12a9b7e7948c3630ee2 + checksum: 10c0/89c54489783510f86df15756659facade82e849c0cbfb564fe047b82be91c5d2b1b5608a4bfc5237bd7b9fd0e1206e66aa3e4f8cad3ac51e37a098b8492c2fa6 languageName: node linkType: hard -"listr2@npm:8.0.1": - version: 8.0.1 - resolution: "listr2@npm:8.0.1" +"listr2@npm:~8.2.1": + version: 8.2.1 + resolution: "listr2@npm:8.2.1" dependencies: cli-truncate: "npm:^4.0.0" colorette: "npm:^2.0.20" eventemitter3: "npm:^5.0.1" log-update: "npm:^6.0.0" - rfdc: "npm:^1.3.0" + rfdc: "npm:^1.3.1" wrap-ansi: "npm:^9.0.0" - checksum: 10c0/b565d6ceb3a4c2dbe0c1735c0fd907afd0d6f89de21aced8e05187b2d88ca2f8f9ebc5d743885396a00f05f13146f6be744d098a56ce0402cf1cd131485a7ff1 + checksum: 10c0/ac32cba8e5c79bcf0dbbb43c2fcc73e47902320c1fa1891074fefb3aa3dfaeef9c76348da22909f65334ba9bee1140bfc903e2f0c64427dd08ef4ba8f6b1dbd0 languageName: node linkType: hard @@ -11762,16 +11755,6 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:4.0.5, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": - version: 4.0.5 - resolution: "micromatch@npm:4.0.5" - dependencies: - braces: "npm:^3.0.2" - picomatch: "npm:^2.3.1" - checksum: 10c0/3d6505b20f9fa804af5d8c596cb1c5e475b9b0cd05f652c5b56141cf941bd72adaeb7a436fda344235cef93a7f29b7472efc779fcdb83b478eab0867b95cdeff - languageName: node - linkType: hard - "micromatch@npm:^3.0.4, micromatch@npm:^3.1.10, micromatch@npm:^3.1.4": version: 3.1.10 resolution: "micromatch@npm:3.1.10" @@ -11793,6 +11776,16 @@ __metadata: languageName: node linkType: hard +"micromatch@npm:^4.0.4, micromatch@npm:^4.0.5, micromatch@npm:~4.0.7": + version: 4.0.7 + resolution: "micromatch@npm:4.0.7" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10c0/58fa99bc5265edec206e9163a1d2cec5fabc46a5b473c45f4a700adce88c2520456ae35f2b301e4410fb3afb27e9521fb2813f6fc96be0a48a89430e0916a772 + languageName: node + linkType: hard + "miller-rabin@npm:^4.0.0": version: 4.0.1 resolution: "miller-rabin@npm:4.0.1" @@ -12986,10 +12979,10 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0": - version: 1.0.0 - resolution: "picocolors@npm:1.0.0" - checksum: 10c0/20a5b249e331c14479d94ec6817a182fd7a5680debae82705747b2db7ec50009a5f6648d0621c561b0572703f84dbef0858abcbd5856d3c5511426afcb1961f7 +"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1": + version: 1.0.1 + resolution: "picocolors@npm:1.0.1" + checksum: 10c0/c63cdad2bf812ef0d66c8db29583802355d4ca67b9285d846f390cc15c2f6ccb94e8cb7eb6a6e97fc5990a6d3ad4ae42d86c84d3146e667c739a4234ed50d400 languageName: node linkType: hard @@ -13000,7 +12993,7 @@ __metadata: languageName: node linkType: hard -"pidtree@npm:0.6.0": +"pidtree@npm:~0.6.0": version: 0.6.0 resolution: "pidtree@npm:0.6.0" bin: @@ -13069,12 +13062,12 @@ __metadata: linkType: hard "pino-pretty@npm:^11.0.0": - version: 11.0.0 - resolution: "pino-pretty@npm:11.0.0" + version: 11.1.0 + resolution: "pino-pretty@npm:11.1.0" dependencies: colorette: "npm:^2.0.7" dateformat: "npm:^4.6.3" - fast-copy: "npm:^3.0.0" + fast-copy: "npm:^3.0.2" fast-safe-stringify: "npm:^2.1.1" help-me: "npm:^5.0.0" joycon: "npm:^3.1.1" @@ -13084,11 +13077,11 @@ __metadata: pump: "npm:^3.0.0" readable-stream: "npm:^4.0.0" secure-json-parse: "npm:^2.4.0" - sonic-boom: "npm:^3.0.0" + sonic-boom: "npm:^4.0.1" strip-json-comments: "npm:^3.1.1" bin: pino-pretty: bin.js - checksum: 10c0/d42213f3fdf19d92152b0a14683b2bb8443423739c81ab7c1181a5dac0e0ca7621d232c8264ece81edc01106ca2a8e165783daca0a902f0fde480027075d5540 + checksum: 10c0/418be6f854b0d62c83c65e75b0969d5311792bfadeefbfe77d8a7f8c5ba26b8bea40f549222b5f500439f440eb4d6c2fa99d712bdd02881ebae7be3a0193b581 languageName: node linkType: hard @@ -15200,10 +15193,10 @@ __metadata: languageName: node linkType: hard -"rfdc@npm:^1.3.0": - version: 1.3.0 - resolution: "rfdc@npm:1.3.0" - checksum: 10c0/a17fd7b81f42c7ae4cb932abd7b2f677b04cc462a03619fb46945ae1ccae17c3bc87c020ffdde1751cbfa8549860a2883486fdcabc9b9de3f3108af32b69a667 +"rfdc@npm:^1.3.1": + version: 1.3.1 + resolution: "rfdc@npm:1.3.1" + checksum: 10c0/69f65e3ed30970f8055fac9fbbef9ce578800ca19554eab1dcbffe73a4b8aef536bc4248313889cf25e3b4e38b212c721eabe30856575bf2b2bc3d90f8ba93ef languageName: node linkType: hard @@ -15865,15 +15858,6 @@ __metadata: languageName: node linkType: hard -"sonic-boom@npm:^3.0.0": - version: 3.7.0 - resolution: "sonic-boom@npm:3.7.0" - dependencies: - atomic-sleep: "npm:^1.0.0" - checksum: 10c0/57a3d560efb77f4576db111168ee2649c99e7869fda6ce0ec2a4e5458832d290ba58d74b073ddb5827d9a30f96d23cff79157993d919e1a6d5f28d8b6391c7f0 - languageName: node - linkType: hard - "sonic-boom@npm:^4.0.1": version: 4.0.1 resolution: "sonic-boom@npm:4.0.1" @@ -16180,7 +16164,7 @@ __metadata: languageName: node linkType: hard -"string-argv@npm:0.3.2": +"string-argv@npm:~0.3.2": version: 0.3.2 resolution: "string-argv@npm:0.3.2" checksum: 10c0/75c02a83759ad1722e040b86823909d9a2fc75d15dd71ec4b537c3560746e33b5f5a07f7332d1e3f88319909f82190843aa2f0a0d8c8d591ec08e93d5b8dec82 @@ -16504,14 +16488,14 @@ __metadata: linkType: hard "stylelint@npm:^16.0.2": - version: 16.5.0 - resolution: "stylelint@npm:16.5.0" + version: 16.6.0 + resolution: "stylelint@npm:16.6.0" dependencies: - "@csstools/css-parser-algorithms": "npm:^2.6.1" - "@csstools/css-tokenizer": "npm:^2.2.4" - "@csstools/media-query-list-parser": "npm:^2.1.9" - "@csstools/selector-specificity": "npm:^3.0.3" - "@dual-bundle/import-meta-resolve": "npm:^4.0.0" + "@csstools/css-parser-algorithms": "npm:^2.6.3" + "@csstools/css-tokenizer": "npm:^2.3.1" + "@csstools/media-query-list-parser": "npm:^2.1.11" + "@csstools/selector-specificity": "npm:^3.1.1" + "@dual-bundle/import-meta-resolve": "npm:^4.1.0" balanced-match: "npm:^2.0.0" colord: "npm:^2.9.3" cosmiconfig: "npm:^9.0.0" @@ -16528,16 +16512,16 @@ __metadata: ignore: "npm:^5.3.1" imurmurhash: "npm:^0.1.4" is-plain-object: "npm:^5.0.0" - known-css-properties: "npm:^0.30.0" + known-css-properties: "npm:^0.31.0" mathml-tag-names: "npm:^2.1.3" meow: "npm:^13.2.0" micromatch: "npm:^4.0.5" normalize-path: "npm:^3.0.0" - picocolors: "npm:^1.0.0" + picocolors: "npm:^1.0.1" postcss: "npm:^8.4.38" postcss-resolve-nested-selector: "npm:^0.1.1" postcss-safe-parser: "npm:^7.0.0" - postcss-selector-parser: "npm:^6.0.16" + postcss-selector-parser: "npm:^6.1.0" postcss-value-parser: "npm:^4.2.0" resolve-from: "npm:^5.0.0" string-width: "npm:^4.2.3" @@ -16548,7 +16532,7 @@ __metadata: write-file-atomic: "npm:^5.0.1" bin: stylelint: bin/stylelint.mjs - checksum: 10c0/9281693ff6c1918e07fdcf7a950531f79678a28261a0d5bd36ca2fcf524e53d7305158d20ba890f5dd01c0ff90c09a13453dce2fe6887f4c157d8c2c0acf3666 + checksum: 10c0/acfb7983a0b71677d066b2aa570eefdac0a7be2e21351bac8884b8156deaeec19e53ad128ae7ae7933c79f6045f1de8d759ba06cfbc373b2711015860805a3e7 languageName: node linkType: hard @@ -18442,13 +18426,6 @@ __metadata: languageName: node linkType: hard -"yaml@npm:2.3.4": - version: 2.3.4 - resolution: "yaml@npm:2.3.4" - checksum: 10c0/cf03b68f8fef5e8516b0f0b54edaf2459f1648317fc6210391cf606d247e678b449382f4bd01f77392538429e306c7cba8ff46ff6b37cac4de9a76aff33bd9e1 - languageName: node - linkType: hard - "yaml@npm:^1.10.0": version: 1.10.2 resolution: "yaml@npm:1.10.2" @@ -18456,6 +18433,15 @@ __metadata: languageName: node linkType: hard +"yaml@npm:~2.4.2": + version: 2.4.2 + resolution: "yaml@npm:2.4.2" + bin: + yaml: bin.mjs + checksum: 10c0/280ddb2e43ffa7d91a95738e80c8f33e860749cdc25aa6d9e4d350a28e174fd7e494e4aa023108aaee41388e451e3dc1292261d8f022aabcf90df9c63d647549 + languageName: node + linkType: hard + "yargs-parser@npm:^13.1.2": version: 13.1.2 resolution: "yargs-parser@npm:13.1.2" From e5c3dc33a29d9f104b7101fb872da52114a38112 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 11:35:45 +0200 Subject: [PATCH 250/658] New Crowdin Translations (automated) (#30421) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/lt.json | 1 + app/javascript/mastodon/locales/nn.json | 2 +- app/javascript/mastodon/locales/pt-BR.json | 1 + app/javascript/mastodon/locales/si.json | 7 +++++++ config/locales/ja.yml | 2 ++ config/locales/lt.yml | 2 ++ config/locales/nn.yml | 12 ++++++------ config/locales/pt-BR.yml | 2 ++ config/locales/si.yml | 12 ++++++------ config/locales/simple_form.lt.yml | 2 ++ config/locales/simple_form.nn.yml | 6 +++--- config/locales/simple_form.si.yml | 2 +- config/locales/simple_form.uk.yml | 5 +++++ config/locales/th.yml | 1 + config/locales/uk.yml | 2 ++ 15 files changed, 42 insertions(+), 17 deletions(-) diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 0f42e97fcf..5fc7d32869 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -466,6 +466,7 @@ "notification.follow_request": "{name} paprašė tave sekti", "notification.mention": "{name} paminėjo tave", "notification.moderation-warning.learn_more": "Sužinoti daugiau", + "notification.moderation_warning": "Gavai prižiūrėjimo įspėjimą", "notification.moderation_warning.action_delete_statuses": "Kai kurie tavo įrašai buvo pašalintos.", "notification.moderation_warning.action_disable": "Tavo paskyra buvo išjungta.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Kai kurie tavo įrašai buvo pažymėtos kaip jautrios.", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 3316e7af81..3711cc0ae3 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -673,7 +673,7 @@ "search.quick_action.account_search": "Profiler som samsvarer med {x}", "search.quick_action.go_to_account": "Gå til profil {x}", "search.quick_action.go_to_hashtag": "Gå til emneknagg {x}", - "search.quick_action.open_url": "Åpne URL i Mastodon", + "search.quick_action.open_url": "Opne adressa i Mastodon", "search.quick_action.status_search": "Innlegg som samsvarer med {x}", "search.search_or_paste": "Søk eller lim inn URL", "search_popout.full_text_search_disabled_message": "Ikkje tilgjengeleg på {domain}.", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 1a6de08359..b11daeaaa7 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -474,6 +474,7 @@ "notification.follow_request": "{name} quer te seguir", "notification.mention": "{name} te mencionou", "notification.moderation-warning.learn_more": "Aprender mais", + "notification.moderation_warning": "Você recebeu um aviso de moderação", "notification.moderation_warning.action_delete_statuses": "Algumas das suas publicações foram removidas.", "notification.moderation_warning.action_disable": "Sua conta foi desativada.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Algumas de suas publicações foram marcadas por ter conteúdo sensível.", diff --git a/app/javascript/mastodon/locales/si.json b/app/javascript/mastodon/locales/si.json index 4cb81a760c..ccbface05a 100644 --- a/app/javascript/mastodon/locales/si.json +++ b/app/javascript/mastodon/locales/si.json @@ -18,6 +18,7 @@ "account.edit_profile": "පැතිකඩ සංස්කරණය", "account.enable_notifications": "@{name} පළ කරන විට මට දැනුම් දෙන්න", "account.endorse": "පැතිකඩෙහි විශේෂාංගය", + "account.featured_tags.last_status_at": "අවසාන ලිපිය: {date}", "account.featured_tags.last_status_never": "ලිපි නැත", "account.follow": "අනුගමනය", "account.followers": "අනුගාමිකයින්", @@ -104,6 +105,7 @@ "compose_form.poll.duration": "මත විමසීමේ කාලය", "compose_form.poll.switch_to_multiple": "තේරීම් කිහිපයකට මත විමසුම වෙනස් කරන්න", "compose_form.poll.switch_to_single": "තනි තේරීමකට මත විමසුම වෙනස් කරන්න", + "compose_form.publish": "ප්‍රකාශනය", "compose_form.publish_form": "නව ලිපිය", "compose_form.spoiler.marked": "අන්තර්ගත අවවාදය ඉවත් කරන්න", "compose_form.spoiler.unmarked": "අන්තර්ගත අවවාදයක් එක් කරන්න", @@ -154,6 +156,7 @@ "empty_column.bookmarked_statuses": "ඔබ සතුව පොත්යොමු තබන ලද ලිපි කිසිවක් නැත. ඔබ පොත්යොමුවක් තබන විට, එය මෙහි දිස්වනු ඇත.", "empty_column.domain_blocks": "අවහිර කරන ලද වසම් නැත.", "empty_column.explore_statuses": "දැන් කිසිවක් නැඹුරු නොවේ. පසුව නැවත පරීක්ෂා කරන්න!", + "empty_column.favourited_statuses": "ඔබ සතුව ප්‍රියතම ලිපි කිසිවක් නැත. ඔබ යමකට ප්‍රිය කළ විට එය මෙහි පෙන්වනු ඇත.", "empty_column.follow_requests": "ඔබට තවමත් අනුගමන ඉල්ලීම් ලැබී නැත. ඉල්ලීමක් ලැබුණු විට, එය මෙහි පෙන්වනු ඇත.", "empty_column.home": "මුල් පිටුව හිස් ය! මෙය පිරවීමට බොහෝ පුද්ගලයින් අනුගමනය කරන්න.", "empty_column.lists": "ඔබට තවමත් ලැයිස්තු කිසිවක් නැත. ඔබ එකක් සාදන විට, එය මෙහි පෙන්වනු ඇත.", @@ -205,6 +208,7 @@ "interaction_modal.on_this_server": "මෙම සේවාදායකයෙහි", "interaction_modal.title.favourite": "{name}ගේ ලිපිය ප්‍රිය කරන්න", "interaction_modal.title.follow": "{name} අනුගමනය", + "interaction_modal.title.reply": "{name}ගේ ලිපියට පිළිතුරු", "intervals.full.days": "{number, plural, one {දවස් #} other {දවස් #}}", "intervals.full.hours": "{number, plural, one {පැය #} other {පැය #}}", "intervals.full.minutes": "{number, plural, one {විනාඩි #} other {විනාඩි #}}", @@ -239,6 +243,7 @@ "lists.delete": "ලැයිස්තුව මකන්න", "lists.edit": "ලැයිස්තුව සංස්කරණය", "lists.edit.submit": "සිරැසිය සංශෝධනය", + "lists.new.create": "එකතු", "lists.new.title_placeholder": "නව ලැයිස්තුවේ සිරැසිය", "lists.replies_policy.list": "ලැයිස්තුවේ සාමාජිකයින්", "lists.replies_policy.none": "කිසිවෙක් නැත", @@ -266,6 +271,7 @@ "navigation_bar.search": "සොයන්න", "navigation_bar.security": "ආරක්ෂාව", "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", + "notification.favourite": "{name} ඔබගේ ලිපියට ප්‍රිය කළා", "notification.follow": "{name} ඔබව අනුගමනය කළා", "notification.mention": "{name} ඔබව සඳහන් කර ඇත", "notification.own_poll": "ඔබගේ මත විමසුම නිමයි", @@ -395,6 +401,7 @@ "status.admin_status": "මෙම ලිපිය මැදිහත්කරණ අතුරුමුහුණතෙහි අරින්න", "status.block": "@{name} අවහිර", "status.bookmark": "පොත්යොමුවක්", + "status.copy": "ලිපියට සබැඳියේ පිටපතක්", "status.delete": "මකන්න", "status.detailed_status": "විස්තරාත්මක සංවාද දැක්ම", "status.edit": "සංස්කරණය", diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 6c0fba259c..ec6963517a 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -282,6 +282,7 @@ ja: update_custom_emoji_html: "%{name}さんがカスタム絵文字 %{target}を更新しました" update_domain_block_html: "%{name}さんが%{target}のドメインブロックを更新しました" update_ip_block_html: "%{name} さんがIP %{target} のルールを更新しました" + update_report_html: "%{name}さんが通報 %{target} を更新しました" update_status_html: "%{name}さんが%{target}さんの投稿を更新しました" update_user_role_html: "%{name}さんがロール『%{target}』を変更しました" deleted_account: 削除されたアカウント @@ -933,6 +934,7 @@ ja: delete: 削除 edit_preset: プリセット警告文を編集 empty: まだプリセット警告文が作成されていません。 + title: プリセット警告文 webhooks: add_new: エンドポイントを追加 delete: 削除 diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 8e32ed07bd..f3d71bf6eb 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -291,6 +291,7 @@ lt: update_custom_emoji_html: "%{name} atnaujino jaustuką %{target}" update_domain_block_html: "%{name} atnaujino domeno bloką %{target}" update_ip_block_html: "%{name} pakeitė taisyklę IP %{target}" + update_report_html: "%{name} atnaujino ataskaitą %{target}" update_status_html: "%{name} atnaujino įrašą %{target}" update_user_role_html: "%{name} pakeitė %{target} vaidmenį" deleted_account: ištrinta paskyra @@ -624,6 +625,7 @@ lt: add_new: Pridėti naują delete: Ištrinti edit_preset: Keisti įspėjimo nustatymus + title: Įspėjamieji numatytieji webhooks: description_html: "Webhook leidžia Mastodon siųsti realaus laiko pranešimus apie pasirinktus įvykius į tavo programą, kad programa galėtų automatiškai paleisti reakcijas." events: Įvykiai diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 94efdcb15a..d82c92c262 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -461,13 +461,13 @@ nn: title: Importer domeneblokkeringar no_file: Inga fil vald follow_recommendations: - description_html: "Følgjeforslag hjelper nye brukarar å raskt finna interessant innhald. Om ein brukar ikkje har interagera nok med andre til å danne personlege følgjeforslag, vert disse kontiane føreslått i staden. Dei vert gjenkalkulert på dagleg basis ut frå ei blanding av dei konti med flest nylege engasjement og flest lokale følgjarar for eit gitt språk." + description_html: "Fylgjeforslag hjelper nye brukarar å finna interessant innhald raskt. Om ein brukar ikkje har samhandla nok med andre til å få tilpassa fylgjeforslag, blir desse kontoane føreslått i staden. Dei blir rekna ut på nytt kvar dag ut frå ei blanding av kva kontoar som har mykje nyleg aktivitet og høgast tal på fylgjarar på eit bestemt språk." language: For språk status: Status suppress: Demp følgjeforslag suppressed: Dempa - title: Følgjeforslag - unsuppress: Tilbakestill følgjeforslag + title: Fylgjeforslag + unsuppress: Nullstill fylgjeforslag instances: availability: description_html: @@ -746,7 +746,7 @@ nn: preamble: Tilpasse web-grensesnittet. title: Utsjånad branding: - preamble: Profileringa av tenaren din skil den frå andre tenarar i nettverket. Informasjonen kan bli vist ulike stadar, til dømes i Mastodon sitt web-grensesnitt, i eigne applikasjonar, i førehandsvisningar på andre nettsider, i meldingsappar og så bortetter. På grunn av dette er det best å halde informasjonen enkel, kort og treffande. + preamble: Profileringa av tenaren din skil den frå andre tenarar i nettverket. Informasjonen kan bli vist ulike stader, til dømes i Mastodon sitt web-grensesnitt, i eigne applikasjonar, i førehandsvisningar på andre nettsider, i meldingsappar og så bortetter. På grunn av dette er det best at denne informasjonen er enkel, kort og treffande. title: Profilering captcha_enabled: desc_html: Dette baserer seg på eksterne skript frå hCaptcha, noko som kan vera eit tryggleiks- og personvernsproblem. I tillegg kan dette gjera registreringsprosessen monaleg mindre tilgjengeleg (særleg for folk med nedsett funksjonsevne). Dette gjer at du bør du vurdera alternative tiltak, som til dømes godkjennings- eller invitasjonsbasert registrering. @@ -759,7 +759,7 @@ nn: desc_html: Påverkar alle brukarar som ikkje har justert denne innstillinga sjølve title: Ikkje la brukarar indekserast av søkjemotorar som standard discovery: - follow_recommendations: Følgjeforslag + follow_recommendations: Fylgjeforslag preamble: Å framheva interessant innhald er vitalt i mottakinga av nye brukarar som ikkje nødvendigvis kjenner nokon på Mastodon. Kontroller korleis oppdagingsfunksjonane på tenaren din fungerar. profile_directory: Profilkatalog public_timelines: Offentlege tidsliner @@ -1562,7 +1562,7 @@ nn: activity: Kontoaktivitet confirm_follow_selected_followers: Er du sikker på at du ynskjer å fylgja dei valde fylgjarane? confirm_remove_selected_followers: Er du sikker på at du ynskjer å fjerna dei valde fylgjarane? - confirm_remove_selected_follows: Er du sikker på at du ynskjer å fjerna det valde følgjet? + confirm_remove_selected_follows: Er du sikker på at du ikkje vil fylgja desse? dormant: I dvale follow_failure: Greidde ikkje fylgja alle kontoane du valde. follow_selected_followers: Følg valgte tilhengere diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 6b80edb24e..8d3b53f777 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -285,6 +285,7 @@ pt-BR: update_custom_emoji_html: "%{name} atualizou o emoji %{target}" update_domain_block_html: "%{name} atualizou o bloqueio de domínio de %{target}" update_ip_block_html: "%{name} alterou a regra para o IP %{target}" + update_report_html: "%{name} atualizou o relatório %{target}" update_status_html: "%{name} atualizou a publicação de %{target}" update_user_role_html: "%{name} alterou o cargo %{target}" deleted_account: conta excluída @@ -950,6 +951,7 @@ pt-BR: delete: Excluir edit_preset: Editar o aviso pré-definido empty: Você ainda não definiu nenhuma predefinição de alerta. + title: Predefinições de aviso webhooks: add_new: Adicionar endpoint delete: Excluir diff --git a/config/locales/si.yml b/config/locales/si.yml index 0f714ee146..85e242b630 100644 --- a/config/locales/si.yml +++ b/config/locales/si.yml @@ -66,7 +66,7 @@ si: inbox_url: එන ලිපි URL invite_request_text: එක්වීමට හේතුව invited_by: විසින් ආරාධනා කරන ලදී - ip: අ.ජා. කෙ. (IP) + ip: අ.ජා.කෙ. (IP) joined: එක් වූ දිනය location: all: සියල්ල @@ -87,7 +87,7 @@ si: title: මැදිහත්කරණය moderation_notes: මැදිහත්කරණ සටහන් most_recent_activity: වඩාත්ම මෑත ක්රියාකාරිත්වය - most_recent_ip: මෑත අ.ජා.කෙ. (IP) + most_recent_ip: මෑත අ.ජා.කෙ. no_account_selected: කිසිවක් තෝරා නොගත් බැවින් ගිණුම් කිසිවක් වෙනස් කර නැත no_limits_imposed: සීමාවන් පනවා නැත not_subscribed: දායක වී නැත @@ -160,7 +160,7 @@ si: create_custom_emoji: අභිරුචි ඉමොජි සාදන්න create_domain_allow: වසමකට ඉඩදීම සාදන්න create_email_domain_block: ඊමේල් ඩොමේන් බ්ලොක් එකක් සාදන්න - create_ip_block: අ.ජා. කෙ. (IP) නීතියක් සාදන්න + create_ip_block: අ.ජා.කෙ. නීතියක් සාදන්න create_unavailable_domain: ලබා ගත නොහැකි වසම සාදන්න create_user_role: භූමිකාව සාදන්න demote_user: පරිශීලකයා පහත් කරන්න @@ -473,7 +473,7 @@ si: new: title: නව අ.ජා.කෙ. නීතියක් සාදන්න no_ip_block_selected: IP රීති කිසිවක් තෝරා නොගත් බැවින් වෙනස් කර නැත - title: අ.ජා. කෙ. (IP) නීති + title: අ.ජා.කෙ. (IP) නීති relationships: title: "%{acct}හි සබඳතා" relays: @@ -1239,7 +1239,7 @@ si: current_session: වත්මන් වාරය description: "%{platform} හි %{browser}" explanation: ඔබගේ මාස්ටඩන් ගිණුමට පිවිසීම සඳහා භාවිතා කර තිබෙන අතිරික්සු. - ip: අ.ජා. කෙ. (IP) + ip: අ.ජා.කෙ. platforms: adobe_air: ඇඩෝබි එයාර් android: ඇන්ඩ්‍රොයිඩ් @@ -1399,7 +1399,7 @@ si: details: 'ප්‍රවේශයට අදාළ විස්තර:' explanation: ඔබගේ ගිණුමට නව අ.ජා.කෙ. (IP) ලිපිනයකින් ප්‍රවේශයක් අනාවරණය වී ඇත. further_actions_html: මේ ඔබ නොවේ නම්, වහාම %{action}. ඔබගේ ගිණුම සුරක්‍ෂිතව තබා ගැනීමට ද්වි-සාධකය සබල කරන්න. - subject: ඔබගේ ගිණුමට නව අ.ජා.කෙ. (IP) ලිපිනයකින් ප්‍රවේශ වී ඇත + subject: ඔබගේ ගිණුමට නව අ.ජා.කෙ. ලිපිනයකින් ප්‍රවේශ වී ඇත title: නව ප්‍රවේශයක් warning: appeal: අභියාචනයක් ඉදිරිපත් කරන්න diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index 789121be42..feec37ae00 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -74,8 +74,10 @@ lt: warn: Slėpti filtruojamą turinį po įspėjimu, paminint filtro pavadinimą form_admin_settings: activity_api_enabled: Vietinių paskelbtų įrašų, aktyvių naudotojų ir naujų registracijų skaičiai kas savaitę + app_icon: WEBP, PNG, GIF arba JPG. Pakeičia numatytąją programos piktogramą mobiliuosiuose įrenginiuose pasirinktine piktograma. backups_retention_period: Naudotojai gali generuoti savo įrašų archyvus, kuriuos vėliau galės atsisiųsti. Nustačius teigiamą reikšmę, šie archyvai po nurodyto dienų skaičiaus bus automatiškai ištrinti iš saugyklos. content_cache_retention_period: Visi įrašai iš kitų serverių (įskaitant pakėlimus ir atsakymus) bus ištrinti po nurodyto dienų skaičiaus, neatsižvelgiant į bet kokią vietinio naudotojo sąveiką su tais įrašais. Tai taikoma ir tiems įrašams, kuriuos vietinis naudotojas yra pažymėjęs kaip žymes ar mėgstamus. Privačios paminėjimai tarp naudotojų iš skirtingų instancijų taip pat bus prarastos ir jų bus neįmanoma atkurti. Šis nustatymas skirtas naudoti ypatingos paskirties instancijose, o įgyvendinus jį bendram naudojimui, pažeidžiami daugelio naudotojų lūkesčiai. + favicon: WEBP, PNG, GIF arba JPG. Pakeičia numatytąją Mastodon svetaines piktogramą pasirinktine piktograma. mascot: Pakeičia išplėstinės žiniatinklio sąsajos iliustraciją. media_cache_retention_period: Nuotolinių naudotojų įrašytų įrašų medijos failai talpinami tavo serveryje. Nustačius teigiamą reikšmę, medijos bus ištrinamos po nurodyto dienų skaičiaus. Jei medijos duomenų bus paprašyta po to, kai jie bus ištrinti, jie bus atsiųsti iš naujo, jei šaltinio turinys vis dar prieinamas. Dėl apribojimų, susijusių su nuorodų peržiūros kortelių apklausos dažnumu trečiųjų šalių svetainėse, rekomenduojama nustatyti šią reikšmę ne trumpesnę kaip 14 dienų, kitaip nuorodų peržiūros kortelės nebus atnaujinamos pagal pareikalavimą iki to laiko. peers_api_enabled: Domenų pavadinimų sąrašas, su kuriais šis serveris susidūrė fediverse. Čia nėra duomenų apie tai, ar tu bendrauji su tam tikru serveriu, tik apie tai, kad tavo serveris apie jį žino. Tai naudojama tarnybose, kurios renka federacijos statistiką bendrąja prasme. diff --git a/config/locales/simple_form.nn.yml b/config/locales/simple_form.nn.yml index a93a803221..a200e1206e 100644 --- a/config/locales/simple_form.nn.yml +++ b/config/locales/simple_form.nn.yml @@ -8,8 +8,8 @@ nn: fields: Heimesida di, pronomen, alder, eller kva du måtte ynskje. indexable: Dei offentlege innlegga dine kan dukka opp i søkjeresultat på Mastodon. Folk som har reagert på oinnlegga dine kan uansett søkja gjennom dei. note: 'Du kan @nemne folk eller #emneknaggar.' - show_collections: Andre kan sjå kven du følgjer og kven som følgjer deg. Dei du følgjer kan alltid sjå at du følgjer dei. - unlocked: Alle kan følgje deg utan å måtte spørje om det. Vel bort om du vil gå gjennom førespurnadar om å følgje deg og seie ja eller nei. + show_collections: Andre kan sjå kven du fylgjer og kven som fylgjer deg. Dei du fylgjer kan alltid sjå at du fylgjer dei. + unlocked: Alle kan fylgja deg utan å måtta be om det. Vel bort dersom du vil gå gjennom førespurnader om å fylgja deg og seia ja eller nei til kvar av dei. account_alias: acct: Angi brukarnamn@domene til brukaren du ynskjer å flytta frå account_migration: @@ -148,7 +148,7 @@ nn: name: Merkelapp value: Innhald indexable: Ta med offentlege innlegg i søkjeresultat - show_collections: Vis følgjer og følgjare på profilen + show_collections: Vis dei du fylgjer og dei som fylgjer deg på profilen din unlocked: Godta nye følgjare automatisk account_alias: acct: Brukarnamnet på den gamle kontoen diff --git a/config/locales/simple_form.si.yml b/config/locales/simple_form.si.yml index eb41d263bc..a81ba27bb9 100644 --- a/config/locales/simple_form.si.yml +++ b/config/locales/simple_form.si.yml @@ -190,7 +190,7 @@ si: text: ඔබට එක් වීමට අවශ්‍ය ඇයි? ip_block: comment: අදහස - ip: අ.ජා. කෙ. (IP) + ip: අ.ජා.කෙ. (IP) severities: no_access: ප්‍රවේශය අවහිර කරන්න sign_up_requires_approval: ලියාපදිංචි වීම සීමා කරන්න diff --git a/config/locales/simple_form.uk.yml b/config/locales/simple_form.uk.yml index 1d69f5c579..11337f2f61 100644 --- a/config/locales/simple_form.uk.yml +++ b/config/locales/simple_form.uk.yml @@ -77,10 +77,15 @@ uk: warn: Сховати відфільтрований вміст за попередженням, у якому вказано заголовок фільтра form_admin_settings: activity_api_enabled: Кількість локальних опублікованих дописів, активних і нових користувачів у тижневих розрізах + app_icon: WEBP, PNG, GIF або JPG. Замінює іконку програми за замовчуванням на мобільних пристроях на власну іконку. + backups_retention_period: Користувачі мають можливість створювати архіви своїх дописів, щоб завантажити їх пізніше. Якщо встановлено додатне значення, ці архіви будуть автоматично видалені з вашого сховища через вказану кількість днів. bootstrap_timeline_accounts: Ці облікові записи будуть закріплені в топі пропозицій для нових користувачів. closed_registrations_message: Показується, коли реєстрація закрита + content_cache_retention_period: Усі дописи з інших серверів (включно з коментарями та відповідями) будуть видалені через певну кількість днів, незважаючи на будь-яку локальну взаємодію користувачів з цими дописами. Сюди входять дописи, які локальний користувач позначив як закладки або вибране. Приватні згадки між користувачами з різних інстанцій також будуть втрачені і не підлягатимуть відновленню. Використання цього параметра призначено для екземплярів спеціального призначення і порушує багато очікувань користувачів, якщо його застосовано для загального використання. custom_css: Ви можете застосувати користувацькі стилі у вебверсії Mastodon. + favicon: WEBP, PNG, GIF або JPG. Замінює стандартну піктограму Mastodon на власну піктограму. mascot: Змінює ілюстрацію в розширеному вебінтерфейсі. + media_cache_retention_period: Медіафайли з дописів віддалених користувачів кешуються на вашому сервері. Якщо встановлено додатне значення, медіа буде видалено через вказану кількість днів. Якщо медіа-дані будуть запитані після видалення, вони будуть завантажені повторно, якщо вихідний вміст все ще доступний. Через обмеження на частоту опитування карток попереднього перегляду посилань на сторонніх сайтах, рекомендується встановити це значення не менше 14 днів, інакше картки попереднього перегляду посилань не будуть оновлюватися на вимогу раніше цього часу. peers_api_enabled: Список доменів імен цього сервера з'явився у федівсесвіті. Сюди не входять дані чи ви пов'язані федерацією з цим сервером, а лише відомості, що вашому серверу відомо про нього. Його використовують служби, які збирають загальну статистику про федерації. profile_directory: У каталозі профілів перераховані всі користувачі, які погодились бути видимими. require_invite_text: Якщо реєстрація вимагає власноручного затвердження, зробіть текстове поле «Чому ви хочете приєднатися?» обов'язковим, а не додатковим diff --git a/config/locales/th.yml b/config/locales/th.yml index 3ca4f09733..bafcd30dee 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -934,6 +934,7 @@ th: delete: ลบ edit_preset: แก้ไขคำเตือนที่ตั้งไว้ล่วงหน้า empty: คุณยังไม่ได้กำหนดคำเตือนที่ตั้งไว้ล่วงหน้าใด ๆ + title: คำเตือนที่ตั้งไว้ล่วงหน้า webhooks: add_new: เพิ่มปลายทาง delete: ลบ diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 5baaa93870..c4f4a26380 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -291,6 +291,7 @@ uk: update_custom_emoji_html: "%{name} оновлює емодзі %{target}" update_domain_block_html: "%{name} оновлює блокування домену для %{target}" update_ip_block_html: "%{name} змінює правило для IP %{target}" + update_report_html: "%{name} оновлений звіт %{target}" update_status_html: "%{name} оновлює допис %{target}" update_user_role_html: "%{name} змінює роль %{target}" deleted_account: видалений обліковий запис @@ -984,6 +985,7 @@ uk: delete: Видалити edit_preset: Редагувати шаблон попередження empty: Ви ще не визначили жодних попереджень. + title: Попереджувальні пресети webhooks: add_new: Додати кінцеву точку delete: Видалити From 15480643e11b32536d9da736ad5cf357ccfb8405 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 11:36:59 +0200 Subject: [PATCH 251/658] chore(deps): update dependency @types/react to v18.3.3 (#30441) 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 ad07e4e426..54cd764e68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3976,12 +3976,12 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7": - version: 18.3.2 - resolution: "@types/react@npm:18.3.2" + version: 18.3.3 + resolution: "@types/react@npm:18.3.3" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10c0/9fb2f1fcf7e889ee4ea7c3c5978df595c66e770e5fd3a245dbdd2589b9b911524c11dab25a6275d8af4e336e4cb5fa850d447884b84c335a187a338c89df99ba + checksum: 10c0/fe455f805c5da13b89964c3d68060cebd43e73ec15001a68b34634604a78140e6fc202f3f61679b9d809dde6d7a7c2cb3ed51e0fd1462557911db09879b55114 languageName: node linkType: hard From 0ef5dc2b2047361c79fde8a3ee3c4683d7541034 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 11:40:37 +0200 Subject: [PATCH 252/658] fix(deps): update dependency jsdom to v24.1.0 (#30431) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 59 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/yarn.lock b/yarn.lock index 54cd764e68..aa0b26c028 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9392,13 +9392,13 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "http-proxy-agent@npm:7.0.0" +"http-proxy-agent@npm:^7.0.0, http-proxy-agent@npm:^7.0.2": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" dependencies: agent-base: "npm:^7.1.0" debug: "npm:^4.3.4" - checksum: 10c0/a11574ff39436cee3c7bc67f259444097b09474605846ddd8edf0bf4ad8644be8533db1aa463426e376865047d05dc22755e638632819317c0c2f1b2196657c8 + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 languageName: node linkType: hard @@ -9442,13 +9442,13 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.2": - version: 7.0.2 - resolution: "https-proxy-agent@npm:7.0.2" +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.4": + version: 7.0.4 + resolution: "https-proxy-agent@npm:7.0.4" dependencies: agent-base: "npm:^7.0.2" debug: "npm:4" - checksum: 10c0/7735eb90073db087e7e79312e3d97c8c04baf7ea7ca7b013382b6a45abbaa61b281041a98f4e13c8c80d88f843785bcc84ba189165b4b4087b1e3496ba656d77 + checksum: 10c0/bc4f7c38da32a5fc622450b6cb49a24ff596f9bd48dcedb52d2da3fa1c1a80e100fb506bd59b326c012f21c863c69b275c23de1a01d0b84db396822fdf25e52b languageName: node linkType: hard @@ -11010,36 +11010,36 @@ __metadata: linkType: hard "jsdom@npm:^24.0.0": - version: 24.0.0 - resolution: "jsdom@npm:24.0.0" + version: 24.1.0 + resolution: "jsdom@npm:24.1.0" dependencies: cssstyle: "npm:^4.0.1" data-urls: "npm:^5.0.0" decimal.js: "npm:^10.4.3" form-data: "npm:^4.0.0" html-encoding-sniffer: "npm:^4.0.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.2" + http-proxy-agent: "npm:^7.0.2" + https-proxy-agent: "npm:^7.0.4" is-potential-custom-element-name: "npm:^1.0.1" - nwsapi: "npm:^2.2.7" + nwsapi: "npm:^2.2.10" parse5: "npm:^7.1.2" - rrweb-cssom: "npm:^0.6.0" + rrweb-cssom: "npm:^0.7.0" saxes: "npm:^6.0.0" symbol-tree: "npm:^3.2.4" - tough-cookie: "npm:^4.1.3" + tough-cookie: "npm:^4.1.4" w3c-xmlserializer: "npm:^5.0.0" webidl-conversions: "npm:^7.0.0" whatwg-encoding: "npm:^3.1.1" whatwg-mimetype: "npm:^4.0.0" whatwg-url: "npm:^14.0.0" - ws: "npm:^8.16.0" + ws: "npm:^8.17.0" xml-name-validator: "npm:^5.0.0" peerDependencies: canvas: ^2.11.2 peerDependenciesMeta: canvas: optional: true - checksum: 10c0/7b35043d7af39ad6dcaef0fa5679d8c8a94c6c9b6cc4a79222b7c9987d57ab7150c50856684ae56b473ab28c7d82aec0fb7ca19dcbd4c3f46683c807d717a3af + checksum: 10c0/34eadd8a7ae20c1505abe7a0f3988b2f0881cce7e27d75c4f5224f440f81f8ac08f4f449695b0f4178f048ed1c1709f3594e9d3f2fe0406c28e8da6eddd44f5a languageName: node linkType: hard @@ -12332,10 +12332,10 @@ __metadata: languageName: node linkType: hard -"nwsapi@npm:^2.2.2, nwsapi@npm:^2.2.7": - version: 2.2.7 - resolution: "nwsapi@npm:2.2.7" - checksum: 10c0/44be198adae99208487a1c886c0a3712264f7bbafa44368ad96c003512fed2753d4e22890ca1e6edb2690c3456a169f2a3c33bfacde1905cf3bf01c7722464db +"nwsapi@npm:^2.2.10, nwsapi@npm:^2.2.2": + version: 2.2.10 + resolution: "nwsapi@npm:2.2.10" + checksum: 10c0/43dfa150387bd2a578e37556d0ae3330d5617f99e5a7b64e3400d4c2785620762aa6169caf8f5fbce17b7ef29c372060b602594320c374fba0a39da4163d77ed languageName: node linkType: hard @@ -15264,6 +15264,13 @@ __metadata: languageName: node linkType: hard +"rrweb-cssom@npm:^0.7.0": + version: 0.7.0 + resolution: "rrweb-cssom@npm:0.7.0" + checksum: 10c0/278350b1f383f76db20e37394361b709740bd4f5f27f924e1c3c3fdd7112b2ae37ed9bc7cee63776f7df395b9b0f644d1f8be104990e3028d276a3288cd7e564 + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -16933,15 +16940,15 @@ __metadata: languageName: node linkType: hard -"tough-cookie@npm:^4.1.2, tough-cookie@npm:^4.1.3": - version: 4.1.3 - resolution: "tough-cookie@npm:4.1.3" +"tough-cookie@npm:^4.1.2, tough-cookie@npm:^4.1.4": + version: 4.1.4 + resolution: "tough-cookie@npm:4.1.4" dependencies: psl: "npm:^1.1.33" punycode: "npm:^2.1.1" universalify: "npm:^0.2.0" url-parse: "npm:^1.5.3" - checksum: 10c0/4fc0433a0cba370d57c4b240f30440c848906dee3180bb6e85033143c2726d322e7e4614abb51d42d111ebec119c4876ed8d7247d4113563033eebbc1739c831 + checksum: 10c0/aca7ff96054f367d53d1e813e62ceb7dd2eda25d7752058a74d64b7266fd07be75908f3753a32ccf866a2f997604b414cfb1916d6e7f69bc64d9d9939b0d6c45 languageName: node linkType: hard @@ -18355,7 +18362,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.11.0, ws@npm:^8.12.1, ws@npm:^8.16.0": +"ws@npm:^8.11.0, ws@npm:^8.12.1, ws@npm:^8.17.0": version: 8.17.0 resolution: "ws@npm:8.17.0" peerDependencies: From 87156f57b5b7b71be8a40e9cc568a87583b55144 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Mon, 27 May 2024 05:41:45 -0400 Subject: [PATCH 253/658] Enable Style/StringConcatenation (#30428) --- .rubocop_todo.yml | 6 ------ config/initializers/paperclip.rb | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 064f622085..a70caad8c5 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -176,12 +176,6 @@ Style/SafeNavigation: Exclude: - 'app/models/concerns/account/finder_concern.rb' -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: Mode. -Style/StringConcatenation: - Exclude: - - 'config/initializers/paperclip.rb' - # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: WordRegex. # SupportedStyles: percent, brackets diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index b54fc6cf0c..5b9365a530 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -13,7 +13,7 @@ end Paperclip.interpolates :prefix_path do |attachment, _style| if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local? - 'cache' + File::SEPARATOR + "cache#{File::SEPARATOR}" else '' end @@ -159,7 +159,7 @@ else Paperclip::Attachment.default_options.merge!( storage: :filesystem, path: File.join(ENV.fetch('PAPERCLIP_ROOT_PATH', File.join(':rails_root', 'public', 'system')), ':prefix_path:class', ':attachment', ':id_partition', ':style', ':filename'), - url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + '/:prefix_url:class/:attachment/:id_partition/:style/:filename' + url: "#{ENV.fetch('PAPERCLIP_ROOT_URL', '/system')}/:prefix_url:class/:attachment/:id_partition/:style/:filename" ) end From c61e356475cf5df85f067a951abf404b93795f19 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 27 May 2024 05:49:44 -0400 Subject: [PATCH 254/658] Add `Status::MEDIA_ATTACHMENTS_LIMIT` configuration constant (#30433) --- app/lib/activitypub/activity/create.rb | 4 ++-- app/models/status.rb | 2 ++ app/serializers/rest/instance_serializer.rb | 2 +- app/serializers/rest/v1/instance_serializer.rb | 2 +- app/services/activitypub/process_status_update_service.rb | 2 +- app/services/post_status_service.rb | 4 ++-- app/services/update_status_service.rb | 4 ++-- spec/requests/api/v2/instance_spec.rb | 2 +- spec/services/post_status_service_spec.rb | 5 +++-- 9 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 85195f4c39..7ec7e84bd1 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -110,7 +110,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def process_status_params @status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url, object: @object) - attachment_ids = process_attachments.take(4).map(&:id) + attachment_ids = process_attachments.take(Status::MEDIA_ATTACHMENTS_LIMIT).map(&:id) @params = { uri: @status_parser.uri, @@ -260,7 +260,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity as_array(@object['attachment']).each do |attachment| media_attachment_parser = ActivityPub::Parser::MediaAttachmentParser.new(attachment) - next if media_attachment_parser.remote_url.blank? || media_attachments.size >= 4 + next if media_attachment_parser.remote_url.blank? || media_attachments.size >= Status::MEDIA_ATTACHMENTS_LIMIT begin media_attachment = MediaAttachment.create( diff --git a/app/models/status.rb b/app/models/status.rb index 72a8d6c40e..9d09fa5fee 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -39,6 +39,8 @@ class Status < ApplicationRecord include Status::SnapshotConcern include Status::ThreadingConcern + MEDIA_ATTACHMENTS_LIMIT = 4 + rate_limit by: :account, family: :statuses self.discard_column = :deleted_at diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 42b73f4387..8df79db6c7 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -59,7 +59,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer statuses: { max_characters: StatusLengthValidator::MAX_CHARS, - max_media_attachments: 4, + max_media_attachments: Status::MEDIA_ATTACHMENTS_LIMIT, characters_reserved_per_url: StatusLengthValidator::URL_PLACEHOLDER_CHARS, }, diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index fdf939cfc3..636925b973 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -64,7 +64,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer statuses: { max_characters: StatusLengthValidator::MAX_CHARS, - max_media_attachments: 4, + max_media_attachments: Status::MEDIA_ATTACHMENTS_LIMIT, characters_reserved_per_url: StatusLengthValidator::URL_PLACEHOLDER_CHARS, }, diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index fb2b33114e..1dbed27f28 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -73,7 +73,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService as_array(@json['attachment']).each do |attachment| media_attachment_parser = ActivityPub::Parser::MediaAttachmentParser.new(attachment) - next if media_attachment_parser.remote_url.blank? || @next_media_attachments.size > 4 + next if media_attachment_parser.remote_url.blank? || @next_media_attachments.size > Status::MEDIA_ATTACHMENTS_LIMIT begin media_attachment = previous_media_attachments.find { |previous_media_attachment| previous_media_attachment.remote_url == media_attachment_parser.remote_url } diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 22a6a24afd..83a9318170 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -130,9 +130,9 @@ class PostStatusService < BaseService return end - raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > 4 || @options[:poll].present? + raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > Status::MEDIA_ATTACHMENTS_LIMIT || @options[:poll].present? - @media = @account.media_attachments.where(status_id: nil).where(id: @options[:media_ids].take(4).map(&:to_i)) + @media = @account.media_attachments.where(status_id: nil).where(id: @options[:media_ids].take(Status::MEDIA_ATTACHMENTS_LIMIT).map(&:to_i)) raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if @media.size > 1 && @media.find(&:audio_or_video?) raise Mastodon::ValidationError, I18n.t('media_attachments.validations.not_ready') if @media.any?(&:not_processed?) diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index cdfe283659..dc7d177e2d 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -69,9 +69,9 @@ class UpdateStatusService < BaseService def validate_media! return [] if @options[:media_ids].blank? || !@options[:media_ids].is_a?(Enumerable) - raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > 4 || @options[:poll].present? + raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > Status::MEDIA_ATTACHMENTS_LIMIT || @options[:poll].present? - media_attachments = @status.account.media_attachments.where(status_id: [nil, @status.id]).where(scheduled_status_id: nil).where(id: @options[:media_ids].take(4).map(&:to_i)).to_a + media_attachments = @status.account.media_attachments.where(status_id: [nil, @status.id]).where(scheduled_status_id: nil).where(id: @options[:media_ids].take(Status::MEDIA_ATTACHMENTS_LIMIT).map(&:to_i)).to_a raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if media_attachments.size > 1 && media_attachments.find(&:audio_or_video?) raise Mastodon::ValidationError, I18n.t('media_attachments.validations.not_ready') if media_attachments.any?(&:not_processed?) diff --git a/spec/requests/api/v2/instance_spec.rb b/spec/requests/api/v2/instance_spec.rb index c5c6a26f49..5c464f09a7 100644 --- a/spec/requests/api/v2/instance_spec.rb +++ b/spec/requests/api/v2/instance_spec.rb @@ -45,7 +45,7 @@ describe 'Instances' do ), statuses: include( max_characters: StatusLengthValidator::MAX_CHARS, - max_media_attachments: 4 # TODO, move to constant somewhere + max_media_attachments: Status::MEDIA_ATTACHMENTS_LIMIT ), polls: include( max_options: PollValidator::MAX_OPTIONS diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index 18891bf118..11bf4c30ea 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -228,14 +228,15 @@ RSpec.describe PostStatusService do expect(media.reload.status).to be_nil end - it 'does not allow attaching more than 4 files' do + it 'does not allow attaching more files than configured limit' do + stub_const('Status::MEDIA_ATTACHMENTS_LIMIT', 1) account = Fabricate(:account) expect do subject.call( account, text: 'test status update', - media_ids: Array.new(5) { Fabricate(:media_attachment, account: account) }.map(&:id) + media_ids: Array.new(2) { Fabricate(:media_attachment, account: account) }.map(&:id) ) end.to raise_error( Mastodon::ValidationError, From ed99923138311fa07d4185a9132c72e618fd21fd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 11:57:19 +0200 Subject: [PATCH 255/658] chore(deps): update eslint (non-major) (#30444) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 197 ++++++++++++++++++--------------------------------- 2 files changed, 70 insertions(+), 129 deletions(-) diff --git a/package.json b/package.json index f38076d4c6..f84d45c32e 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "eslint-plugin-import": "~2.29.0", "eslint-plugin-jsdoc": "^48.0.0", "eslint-plugin-jsx-a11y": "~6.8.0", - "eslint-plugin-promise": "~6.1.1", + "eslint-plugin-promise": "~6.2.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "husky": "^9.0.11", diff --git a/yarn.lock b/yarn.lock index aa0b26c028..da5bf1dca2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2248,16 +2248,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.18.2": - version: 1.18.2 - resolution: "@formatjs/ecma402-abstract@npm:1.18.2" - dependencies: - "@formatjs/intl-localematcher": "npm:0.5.4" - tslib: "npm:^2.4.0" - checksum: 10c0/87afb37dd937555e712ca85d5142a9083d617c491d1dddf8d660fdfb6186272d2bc75b78809b076388d26f016200c8bddbce73281fd707eb899da2bf3bc9b7ca - languageName: node - linkType: hard - "@formatjs/ecma402-abstract@npm:2.0.0": version: 2.0.0 resolution: "@formatjs/ecma402-abstract@npm:2.0.0" @@ -2277,17 +2267,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-messageformat-parser@npm:2.7.6": - version: 2.7.6 - resolution: "@formatjs/icu-messageformat-parser@npm:2.7.6" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.2" - "@formatjs/icu-skeleton-parser": "npm:1.8.0" - tslib: "npm:^2.4.0" - checksum: 10c0/9fc72c2075333a969601e2be4260638940b1abefd1a5fc15b93b0b10d2319c9df5778aa51fc2a173ce66ca5e8a47b4b64caca85a32d0eb6095e16e8d65cb4b00 - languageName: node - linkType: hard - "@formatjs/icu-messageformat-parser@npm:2.7.8": version: 2.7.8 resolution: "@formatjs/icu-messageformat-parser@npm:2.7.8" @@ -2299,16 +2278,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-skeleton-parser@npm:1.8.0": - version: 1.8.0 - resolution: "@formatjs/icu-skeleton-parser@npm:1.8.0" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.18.2" - tslib: "npm:^2.4.0" - checksum: 10c0/10956732d70cc67049d216410b5dc3ef048935d1ea2ae76f5755bb9d0243af37ddeabd5d140ddbf5f6c7047068c3d02a05f93c68a89cedfaf7488d5062885ea4 - languageName: node - linkType: hard - "@formatjs/icu-skeleton-parser@npm:1.8.2": version: 1.8.2 resolution: "@formatjs/icu-skeleton-parser@npm:1.8.2" @@ -2381,26 +2350,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ts-transformer@npm:3.13.12": - version: 3.13.12 - resolution: "@formatjs/ts-transformer@npm:3.13.12" - dependencies: - "@formatjs/icu-messageformat-parser": "npm:2.7.6" - "@types/json-stable-stringify": "npm:^1.0.32" - "@types/node": "npm:14 || 16 || 17" - chalk: "npm:^4.0.0" - json-stable-stringify: "npm:^1.0.1" - tslib: "npm:^2.4.0" - typescript: "npm:5" - peerDependencies: - ts-jest: ">=27" - peerDependenciesMeta: - ts-jest: - optional: true - checksum: 10c0/68f72ee6379b87b7ef6340e118a5370cb2fa18cbbae08f5f3d10893803a52f0533e644002e0b5e9ffeded5b2f0aa9daad6adf8b487b10f5d2b61f9fb3fed0dbd - languageName: node - linkType: hard - "@formatjs/ts-transformer@npm:3.13.14": version: 3.13.14 resolution: "@formatjs/ts-transformer@npm:3.13.14" @@ -2873,7 +2822,7 @@ __metadata: eslint-plugin-import: "npm:~2.29.0" eslint-plugin-jsdoc: "npm:^48.0.0" eslint-plugin-jsx-a11y: "npm:~6.8.0" - eslint-plugin-promise: "npm:~6.1.1" + eslint-plugin-promise: "npm:~6.2.0" eslint-plugin-react: "npm:^7.33.2" eslint-plugin-react-hooks: "npm:^4.6.0" file-loader: "npm:^6.2.0" @@ -3733,7 +3682,7 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db @@ -4009,7 +3958,7 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.5.0, @types/semver@npm:^7.5.8": +"@types/semver@npm:^7.5.0": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" checksum: 10c0/8663ff927234d1c5fcc04b33062cb2b9fcfbe0f5f351ed26c4d1e1581657deebd506b41ff7fdf89e787e3d33ce05854bc01686379b89e9c49b564c4cfa988efa @@ -4160,19 +4109,17 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^7.0.0": - version: 7.8.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.8.0" + version: 7.10.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.10.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.8.0" - "@typescript-eslint/type-utils": "npm:7.8.0" - "@typescript-eslint/utils": "npm:7.8.0" - "@typescript-eslint/visitor-keys": "npm:7.8.0" - debug: "npm:^4.3.4" + "@typescript-eslint/scope-manager": "npm:7.10.0" + "@typescript-eslint/type-utils": "npm:7.10.0" + "@typescript-eslint/utils": "npm:7.10.0" + "@typescript-eslint/visitor-keys": "npm:7.10.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" - semver: "npm:^7.6.0" ts-api-utils: "npm:^1.3.0" peerDependencies: "@typescript-eslint/parser": ^7.0.0 @@ -4180,25 +4127,25 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/37ca22620d1834ff0baa28fa4b8fd92039a3903cb95748353de32d56bae2a81ce50d1bbaed27487eebc884e0a0f9387fcb0f1647593e4e6df5111ef674afa9f0 + checksum: 10c0/bf3f0118ea5961c3eb01894678246458a329d82dda9ac7c2f5bfe77896410d05a08a4655e533bcb1ed2a3132ba6421981ec8c2ed0a3545779d9603ea231947ae languageName: node linkType: hard "@typescript-eslint/parser@npm:^7.0.0": - version: 7.8.0 - resolution: "@typescript-eslint/parser@npm:7.8.0" + version: 7.10.0 + resolution: "@typescript-eslint/parser@npm:7.10.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.8.0" - "@typescript-eslint/types": "npm:7.8.0" - "@typescript-eslint/typescript-estree": "npm:7.8.0" - "@typescript-eslint/visitor-keys": "npm:7.8.0" + "@typescript-eslint/scope-manager": "npm:7.10.0" + "@typescript-eslint/types": "npm:7.10.0" + "@typescript-eslint/typescript-estree": "npm:7.10.0" + "@typescript-eslint/visitor-keys": "npm:7.10.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/0dd994c1b31b810c25e1b755b8d352debb7bf21a31f9a91acaec34acf4e471320bcceaa67cf64c110c0b8f5fac10a037dbabac6ec423e17adf037e59a7bce9c1 + checksum: 10c0/4c4fbf43b5b05d75b766acb803d3dd078c6e080641a77f9e48ba005713466738ea4a71f0564fa3ce520988d65158d14c8c952ba01ccbc431ab4a05935db5ce6d languageName: node linkType: hard @@ -4212,22 +4159,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.8.0": - version: 7.8.0 - resolution: "@typescript-eslint/scope-manager@npm:7.8.0" +"@typescript-eslint/scope-manager@npm:7.10.0": + version: 7.10.0 + resolution: "@typescript-eslint/scope-manager@npm:7.10.0" dependencies: - "@typescript-eslint/types": "npm:7.8.0" - "@typescript-eslint/visitor-keys": "npm:7.8.0" - checksum: 10c0/c253b98e96d4bf0375f473ca2c4d081726f1fd926cdfa65ee14c9ee99cca8eddb763b2d238ac365daa7246bef21b0af38180d04e56e9df7443c0e6f8474d097c + "@typescript-eslint/types": "npm:7.10.0" + "@typescript-eslint/visitor-keys": "npm:7.10.0" + checksum: 10c0/1d4f7ee137b95bd423b5a1b0d03251202dfc19bd8b6adfa5ff5df25fd5aa30e2d8ca50ab0d8d2e92441670ecbc2a82b3c2dbe39a4f268ec1ee1c1e267f7fd1d1 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.8.0": - version: 7.8.0 - resolution: "@typescript-eslint/type-utils@npm:7.8.0" +"@typescript-eslint/type-utils@npm:7.10.0": + version: 7.10.0 + resolution: "@typescript-eslint/type-utils@npm:7.10.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.8.0" - "@typescript-eslint/utils": "npm:7.8.0" + "@typescript-eslint/typescript-estree": "npm:7.10.0" + "@typescript-eslint/utils": "npm:7.10.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependencies: @@ -4235,7 +4182,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/00f6315626b64f7dbc1f7fba6f365321bb8d34141ed77545b2a07970e59a81dbdf768c1e024225ea00953750d74409ddd8a16782fc4a39261e507c04192dacab + checksum: 10c0/55e9a6690f9cedb79d30abb1990b161affaa2684dac246b743223353812c9c1e3fd2d923c67b193c6a3624a07e1c82c900ce7bf5b6b9891c846f04cb480ebd9f languageName: node linkType: hard @@ -4246,10 +4193,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.8.0, @typescript-eslint/types@npm:^7.2.0": - version: 7.8.0 - resolution: "@typescript-eslint/types@npm:7.8.0" - checksum: 10c0/b2fdbfc21957bfa46f7d8809b607ad8c8b67c51821d899064d09392edc12f28b2318a044f0cd5d523d782e84e8f0558778877944964cf38e139f88790cf9d466 +"@typescript-eslint/types@npm:7.10.0, @typescript-eslint/types@npm:^7.2.0": + version: 7.10.0 + resolution: "@typescript-eslint/types@npm:7.10.0" + checksum: 10c0/f01d9330b93cc362ba7967ab5037396f64742076450e1f93139fa69cbe93a6ece3ed55d68ab780c9b7d07ef4a7c645da410305216a2cfc5dec7eba49ee65ab23 languageName: node linkType: hard @@ -4272,12 +4219,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.8.0": - version: 7.8.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.8.0" +"@typescript-eslint/typescript-estree@npm:7.10.0": + version: 7.10.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.10.0" dependencies: - "@typescript-eslint/types": "npm:7.8.0" - "@typescript-eslint/visitor-keys": "npm:7.8.0" + "@typescript-eslint/types": "npm:7.10.0" + "@typescript-eslint/visitor-keys": "npm:7.10.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -4287,24 +4234,21 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/1690b62679685073dcb0f62499f0b52b445b37ae6e12d02aa4acbafe3fb023cf999b01f714b6282e88f84fd934fe3e2eefb21a64455d19c348d22bbc68ca8e47 + checksum: 10c0/6200695834c566e52e2fa7331f1a05019f7815969d8c1e1e237b85a99664d36f41ccc16384eff3f8582a0ecb75f1cc315b56ee9283b818da37f24fa4d42f1d7a languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.8.0": - version: 7.8.0 - resolution: "@typescript-eslint/utils@npm:7.8.0" +"@typescript-eslint/utils@npm:7.10.0": + version: 7.10.0 + resolution: "@typescript-eslint/utils@npm:7.10.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@types/json-schema": "npm:^7.0.15" - "@types/semver": "npm:^7.5.8" - "@typescript-eslint/scope-manager": "npm:7.8.0" - "@typescript-eslint/types": "npm:7.8.0" - "@typescript-eslint/typescript-estree": "npm:7.8.0" - semver: "npm:^7.6.0" + "@typescript-eslint/scope-manager": "npm:7.10.0" + "@typescript-eslint/types": "npm:7.10.0" + "@typescript-eslint/typescript-estree": "npm:7.10.0" peerDependencies: eslint: ^8.56.0 - checksum: 10c0/31fb58388d15b082eb7bd5bce889cc11617aa1131dfc6950471541b3df64c82d1c052e2cccc230ca4ae80456d4f63a3e5dccb79899a8f3211ce36c089b7d7640 + checksum: 10c0/6724471f94f2788f59748f7efa2a3a53ea910099993bee2fa5746ab5acacecdc9fcb110c568b18099ddc946ea44919ed394bff2bd055ba81fc69f5e6297b73bf languageName: node linkType: hard @@ -4335,13 +4279,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.8.0": - version: 7.8.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.8.0" +"@typescript-eslint/visitor-keys@npm:7.10.0": + version: 7.10.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.10.0" dependencies: - "@typescript-eslint/types": "npm:7.8.0" + "@typescript-eslint/types": "npm:7.10.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/5892fb5d9c58efaf89adb225f7dbbb77f9363961f2ff420b6b130bdd102dddd7aa8a16c46a5a71c19889d27b781e966119a89270555ea2cb5653a04d8994123d + checksum: 10c0/049e812bcd28869059d04c7bf3543bb55f5205f468b777439c4f120417fb856fb6024cb1d25291aa12556bd08e84f043a96d754ffb2cde37abb604d6f3c51634 languageName: node linkType: hard @@ -7825,11 +7769,11 @@ __metadata: linkType: hard "eslint-plugin-formatjs@npm:^4.10.1": - version: 4.13.1 - resolution: "eslint-plugin-formatjs@npm:4.13.1" + version: 4.13.3 + resolution: "eslint-plugin-formatjs@npm:4.13.3" dependencies: - "@formatjs/icu-messageformat-parser": "npm:2.7.6" - "@formatjs/ts-transformer": "npm:3.13.12" + "@formatjs/icu-messageformat-parser": "npm:2.7.8" + "@formatjs/ts-transformer": "npm:3.13.14" "@types/eslint": "npm:7 || 8" "@types/picomatch": "npm:^2.3.0" "@typescript-eslint/utils": "npm:^6.18.1" @@ -7841,7 +7785,7 @@ __metadata: unicode-emoji-utils: "npm:^1.2.0" peerDependencies: eslint: 7 || 8 - checksum: 10c0/ce18141dff84e8fe026127085c1a63279acb3a1bc0b70dc1ddce2fc65bb37d68ccf6d097231428745eda2caea42080e1c80a01a1895803155c15123a01bfeee3 + checksum: 10c0/5e98f487a097189e3bdc64b678d19f4c83502c32d7c89a8959eda4ed9cb664bf16f13ad8871be89ca192cb39c1007d6a158c39bbf5b23c56962d949dbe9abfab languageName: node linkType: hard @@ -7873,8 +7817,8 @@ __metadata: linkType: hard "eslint-plugin-jsdoc@npm:^48.0.0": - version: 48.2.4 - resolution: "eslint-plugin-jsdoc@npm:48.2.4" + version: 48.2.6 + resolution: "eslint-plugin-jsdoc@npm:48.2.6" dependencies: "@es-joy/jsdoccomment": "npm:~0.43.0" are-docs-informative: "npm:^0.0.2" @@ -7882,12 +7826,11 @@ __metadata: 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.6.0" + semver: "npm:^7.6.1" spdx-expression-parse: "npm:^4.0.0" peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: 10c0/601c9d6ee41de56102c7813106ceb0b8b8342223670f7add010a8f89753c250cde4cc93e353e3911b7b29677f2634f3f4be45f27abb7a95c6fdbd058adfa3343 + checksum: 10c0/9f01b3000aa31f17767786c62caf62f1e8c4b88bfef04b207d3b1de785be287cc2da3ad16ed32afacd5f6e6a9b76ebf3369069be416ce2228c44cd6d084fcd8f languageName: node linkType: hard @@ -7917,12 +7860,12 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-promise@npm:~6.1.1": - version: 6.1.1 - resolution: "eslint-plugin-promise@npm:6.1.1" +"eslint-plugin-promise@npm:~6.2.0": + version: 6.2.0 + resolution: "eslint-plugin-promise@npm:6.2.0" peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - checksum: 10c0/ec705741c110cd1cb4d702776e1c7f7fe60b671b71f706c88054ab443cf2767aae5a663928fb426373ba1095eaeda312a740a4f880546631f0e0727f298b3393 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + checksum: 10c0/5f42ee774023c089453ecb792076c64c6d0739ea6e9d6cdc9d6a63da5ba928c776e349d01cc110548f2c67045ec55343136aa7eb8b486e4ab145ac016c06a492 languageName: node linkType: hard @@ -15487,14 +15430,12 @@ __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, semver@npm:^7.6.0": - version: 7.6.0 - resolution: "semver@npm:7.6.0" - dependencies: - lru-cache: "npm:^6.0.0" +"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, semver@npm:^7.6.1": + version: 7.6.2 + resolution: "semver@npm:7.6.2" bin: semver: bin/semver.js - checksum: 10c0/fbfe717094ace0aa8d6332d7ef5ce727259815bd8d8815700853f4faf23aacbd7192522f0dc5af6df52ef4fa85a355ebd2f5d39f554bd028200d6cf481ab9b53 + checksum: 10c0/97d3441e97ace8be4b1976433d1c32658f6afaff09f143e52c593bae7eef33de19e3e369c88bd985ce1042c6f441c80c6803078d1de2a9988080b66684cbb30c languageName: node linkType: hard From 32c30bf0fdc8c0d57f4e272a7827daa39faa6313 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 10:05:37 +0200 Subject: [PATCH 256/658] New Crowdin Translations (automated) (#30452) Co-authored-by: GitHub Actions --- config/locales/lt.yml | 18 ++++++++++++++++++ config/locales/vi.yml | 1 + 2 files changed, 19 insertions(+) diff --git a/config/locales/lt.yml b/config/locales/lt.yml index f3d71bf6eb..77fcf42866 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -345,6 +345,8 @@ lt: shortcode: Trumpas kodas shortcode_hint: Bent du ženklai, tik raidiniai skaitmeniniai ženklai bei akcentai(_) title: Asmeniniai jaustukai + uncategorized: Be kategorijos + unlist: Išbraukti iš sąrašo unlisted: Neįtrauktas į sąrašą update_failed_msg: Jaustukas negalėjo būti pakeistas updated_msg: Jaustukas sėkmingai pakeistas! @@ -392,8 +394,16 @@ lt: created_msg: Domenas buvo sėkmingai leistas federacijai. destroyed_msg: Domenas buvo neleistas federacijai. export: Eksportuoti + import: Importuoti + undo: Neleisti federavimo su domenu domain_blocks: add_new: Pridėti naują domeno bloką + confirm_suspension: + cancel: Atšaukti + confirm: Pristabdyti + permanent_action: Atšaukus pristabdymą jokie duomenys ar sąryšiai nebus atkurti. + preamble_html: Jūs pristabdysite %{domain} ir jo subdomenus. + remove_all_data: Taip iš serverio bus pašalintas visas šio domeno paskyrų turinys, medija ir profilio duomenys. created_msg: Domeno užblokavimas nagrinėjamas destroyed_msg: Domeno blokas pašalintas domain: Domenas @@ -411,6 +421,7 @@ lt: silence: Riboti suspend: Pristabdyti title: Naujos domeno blokas + private_comment: Privatus komentaras public_comment: Viešas komentaras public_comment_hint: Komentaras apie šį domeno apribojimą plačiajai visuomenei, jei įjungtas domenų apribojimų sąrašo reklamavimas. reject_media: Atmesti medijos failus @@ -418,6 +429,7 @@ lt: reject_reports: Atmesti ataskaitas reject_reports_hint: Ignoruoti visus skundus, kurie siunčiami iš šio domeno. Neliečia užblokavimu undo: Atkurti domeno bloką + view: Peržiūrėti domeno bloką email_domain_blocks: add_new: Pridėti naują allow_registrations_with_approval: Leisti registracijas su patvirtinimu @@ -429,10 +441,16 @@ lt: title: Naujas el pašto juodojo sąrašo įtraukimas title: El pašto juodasis sąrašas instances: + availability: + title: Prieinamumas back_to_all: Visi + back_to_limited: Apribotas + back_to_warning: Įspėjimas by_domain: Domenas content_policies: + policy: Politika reason: Viešoji priežastis + title: Turinio politika delivery: all: Visi delivery_available: Pristatymas galimas diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 4265c1a33a..459d1bb0d9 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -934,6 +934,7 @@ vi: delete: Xóa bỏ edit_preset: Sửa mẫu có sẵn empty: Bạn chưa thêm mẫu cảnh cáo nào cả. + title: Cảnh báo cài sẵn webhooks: add_new: Thêm endpoint delete: Xóa bỏ From 4a77e477ee50f69160cecec25a68ee88b53dfcf8 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 28 May 2024 10:11:31 -0400 Subject: [PATCH 257/658] Consolidate account scopes for `LOWER` (index using) username/domain queries (#30451) --- app/models/account.rb | 2 + .../account_suggestions/setting_source.rb | 10 ++--- app/models/concerns/account/finder_concern.rb | 41 +++---------------- .../concerns/user/ldap_authenticable.rb | 2 +- app/services/report_service.rb | 2 +- app/validators/unique_username_validator.rb | 5 +-- 6 files changed, 14 insertions(+), 48 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index 3c533822fd..8a990bb831 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -142,6 +142,8 @@ class Account < ApplicationRecord scope :not_excluded_by_account, ->(account) { where.not(id: account.excluded_from_timeline_account_ids) } scope :not_domain_blocked_by_account, ->(account) { where(arel_table[:domain].eq(nil).or(arel_table[:domain].not_in(account.excluded_from_timeline_domains))) } scope :dormant, -> { joins(:account_stat).merge(AccountStat.without_recent_activity) } + scope :with_username, ->(value) { where arel_table[:username].lower.eq(value.to_s.downcase) } + scope :with_domain, ->(value) { where arel_table[:domain].lower.eq(value&.to_s&.downcase) } after_update_commit :trigger_update_webhooks diff --git a/app/models/account_suggestions/setting_source.rb b/app/models/account_suggestions/setting_source.rb index 9f3cd7bd3d..6143481723 100644 --- a/app/models/account_suggestions/setting_source.rb +++ b/app/models/account_suggestions/setting_source.rb @@ -3,7 +3,7 @@ class AccountSuggestions::SettingSource < AccountSuggestions::Source def get(account, limit: DEFAULT_LIMIT) if setting_enabled? - base_account_scope(account).where(setting_to_where_condition).limit(limit).pluck(:id).zip([key].cycle) + base_account_scope(account).merge(setting_to_where_condition).limit(limit).pluck(:id).zip([key].cycle) else [] end @@ -25,11 +25,9 @@ class AccountSuggestions::SettingSource < AccountSuggestions::Source def setting_to_where_condition usernames_and_domains.map do |(username, domain)| - Arel::Nodes::Grouping.new( - Account.arel_table[:username].lower.eq(username.downcase).and( - Account.arel_table[:domain].lower.eq(domain&.downcase) - ) - ) + Account + .with_username(username) + .with_domain(domain) end.reduce(:or) end diff --git a/app/models/concerns/account/finder_concern.rb b/app/models/concerns/account/finder_concern.rb index a7acff1cbb..249a7b5fd1 100644 --- a/app/models/concerns/account/finder_concern.rb +++ b/app/models/concerns/account/finder_concern.rb @@ -25,42 +25,11 @@ module Account::FinderConcern end def find_remote(username, domain) - AccountFinder.new(username, domain).account - end - end - - class AccountFinder - attr_reader :username, :domain - - def initialize(username, domain) - @username = username - @domain = domain - end - - def account - scoped_accounts.order(id: :asc).take - end - - private - - def scoped_accounts - Account.unscoped.tap do |scope| - scope.merge! with_usernames - scope.merge! matching_username - scope.merge! matching_domain - end - end - - def with_usernames - Account.where.not(Account.arel_table[:username].lower.eq '') - end - - def matching_username - Account.where(Account.arel_table[:username].lower.eq username.to_s.downcase) - end - - def matching_domain - Account.where(Account.arel_table[:domain].lower.eq(domain.nil? ? nil : domain.to_s.downcase)) + Account + .with_username(username) + .with_domain(domain) + .order(id: :asc) + .take end end end diff --git a/app/models/concerns/user/ldap_authenticable.rb b/app/models/concerns/user/ldap_authenticable.rb index c8e9fa9348..fc1ee78d09 100644 --- a/app/models/concerns/user/ldap_authenticable.rb +++ b/app/models/concerns/user/ldap_authenticable.rb @@ -22,7 +22,7 @@ module User::LdapAuthenticable safe_username = safe_username.gsub(keys, replacement) end - resource = joins(:account).merge(Account.where(Account.arel_table[:username].lower.eq safe_username.downcase)).take + resource = joins(:account).merge(Account.with_username(safe_username)).take if resource.blank? resource = new( diff --git a/app/services/report_service.rb b/app/services/report_service.rb index fe546c383e..dea6df7b0a 100644 --- a/app/services/report_service.rb +++ b/app/services/report_service.rb @@ -81,7 +81,7 @@ class ReportService < BaseService # If the account making reports is remote, it is likely anonymized so we have to relax the requirements for attaching statuses. domain = @source_account.domain.to_s.downcase - has_followers = @target_account.followers.where(Account.arel_table[:domain].lower.eq(domain)).exists? + has_followers = @target_account.followers.with_domain(domain).exists? visibility = has_followers ? %i(public unlisted private) : %i(public unlisted) scope = @target_account.statuses.with_discarded scope.merge!(scope.where(visibility: visibility).or(scope.where('EXISTS (SELECT 1 FROM mentions m JOIN accounts a ON m.account_id = a.id WHERE lower(a.domain) = ?)', domain))) diff --git a/app/validators/unique_username_validator.rb b/app/validators/unique_username_validator.rb index 09c8fadb55..c417e2f696 100644 --- a/app/validators/unique_username_validator.rb +++ b/app/validators/unique_username_validator.rb @@ -6,10 +6,7 @@ class UniqueUsernameValidator < ActiveModel::Validator def validate(account) return if account.username.blank? - normalized_username = account.username.downcase - normalized_domain = account.domain&.downcase - - scope = Account.where(Account.arel_table[:username].lower.eq normalized_username).where(Account.arel_table[:domain].lower.eq normalized_domain) + scope = Account.with_username(account.username).with_domain(account.domain) scope = scope.where.not(id: account.id) if account.persisted? account.errors.add(:username, :taken) if scope.exists? From 128987ededcbcdf73529d98a4f11c747b2bbe892 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 29 May 2024 01:34:33 +0200 Subject: [PATCH 258/658] Add support for `fediverse:creator` OpenGraph tag (#30398) --- .../api/v1/conversations_controller.rb | 8 ++-- .../features/status/components/card.jsx | 32 +++++++++++--- app/javascript/mastodon/locales/en.json | 1 + .../styles/mastodon/components.scss | 43 +++++++++++++++++++ app/lib/link_details_extractor.rb | 4 ++ app/models/preview_card.rb | 2 + app/models/status.rb | 10 ++--- .../rest/preview_card_serializer.rb | 2 + app/services/fetch_link_card_service.rb | 3 ++ ..._add_author_account_id_to_preview_cards.rb | 10 +++++ db/schema.rb | 5 ++- 11 files changed, 105 insertions(+), 15 deletions(-) create mode 100644 db/migrate/20240522041528_add_author_account_id_to_preview_cards.rb diff --git a/app/controllers/api/v1/conversations_controller.rb b/app/controllers/api/v1/conversations_controller.rb index a95c816e1c..a29b908555 100644 --- a/app/controllers/api/v1/conversations_controller.rb +++ b/app/controllers/api/v1/conversations_controller.rb @@ -38,15 +38,15 @@ class Api::V1::ConversationsController < Api::BaseController def paginated_conversations AccountConversation.where(account: current_account) .includes( - account: :account_stat, + account: [:account_stat, user: :role], last_status: [ :media_attachments, :status_stat, :tags, { - preview_cards_status: :preview_card, - active_mentions: [account: :account_stat], - account: :account_stat, + preview_cards_status: { preview_card: { author_account: [:account_stat, user: :role] } }, + active_mentions: :account, + account: [:account_stat, user: :role], }, ] ) diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index f47861f663..c2f5703b3c 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -6,6 +6,8 @@ import { PureComponent } from 'react'; import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; +import { Link } from 'react-router-dom'; + import Immutable from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; @@ -13,6 +15,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import DescriptionIcon from '@/material-icons/400-24px/description-fill.svg?react'; import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react'; import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; +import { Avatar } from 'mastodon/components/avatar'; import { Blurhash } from 'mastodon/components/blurhash'; import { Icon } from 'mastodon/components/icon'; import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; @@ -56,6 +59,20 @@ const addAutoPlay = html => { return html; }; +const MoreFromAuthor = ({ author }) => ( +
+ + + + + {author.get('display_name')} }} /> +
+); + +MoreFromAuthor.propTypes = { + author: ImmutablePropTypes.map, +}; + export default class Card extends PureComponent { static propTypes = { @@ -136,6 +153,7 @@ export default class Card extends PureComponent { const interactive = card.get('type') === 'video'; const language = card.get('language') || ''; const largeImage = (card.get('image')?.length > 0 && card.get('width') > card.get('height')) || interactive; + const showAuthor = !!card.get('author_account'); const description = (
@@ -146,7 +164,7 @@ export default class Card extends PureComponent { {card.get('title')} - {card.get('author_name').length > 0 ? {card.get('author_name')} }} /> : {card.get('description')}} + {!showAuthor && (card.get('author_name').length > 0 ? {card.get('author_name')} }} /> : {card.get('description')})}
); @@ -235,10 +253,14 @@ export default class Card extends PureComponent { } return ( - - {embed} - {description} - + <> + + {embed} + {description} + + + {showAuthor && } + ); } diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 56e4612c1c..63298d59e3 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Show profile anyway", "limited_account_hint.title": "This profile has been hidden by the moderators of {domain}.", "link_preview.author": "By {name}", + "link_preview.more_from_author": "More from {name}", "lists.account.add": "Add to list", "lists.account.remove": "Remove from list", "lists.delete": "Delete list", diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 859c6e3267..4f36d85aa9 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3896,6 +3896,10 @@ $ui-header-logo-wordmark-width: 99px; border: 1px solid var(--background-border-color); border-radius: 8px; + &.bottomless { + border-radius: 8px 8px 0 0; + } + &__actions { bottom: 0; inset-inline-start: 0; @@ -10223,3 +10227,42 @@ noscript { } } } + +.more-from-author { + font-size: 14px; + color: $darker-text-color; + background: var(--surface-background-color); + border: 1px solid var(--background-border-color); + border-top: 0; + border-radius: 0 0 8px 8px; + padding: 15px; + display: flex; + align-items: center; + gap: 8px; + + .logo { + height: 16px; + color: $darker-text-color; + } + + & > span { + display: flex; + align-items: center; + gap: 8px; + } + + a { + display: inline-flex; + align-items: center; + gap: 4px; + font-weight: 500; + color: $primary-text-color; + text-decoration: none; + + &:hover, + &:focus, + &:active { + color: $highlight-text-color; + } + } +} diff --git a/app/lib/link_details_extractor.rb b/app/lib/link_details_extractor.rb index 07776c3699..2e49d3fb4f 100644 --- a/app/lib/link_details_extractor.rb +++ b/app/lib/link_details_extractor.rb @@ -195,6 +195,10 @@ class LinkDetailsExtractor structured_data&.author_url end + def author_account + opengraph_tag('fediverse:creator') + end + def embed_url valid_url_or_nil(opengraph_tag('twitter:player:stream')) end diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index 9fe02bd168..11fdd9d88a 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -32,6 +32,7 @@ # link_type :integer # published_at :datetime # image_description :string default(""), not null +# author_account_id :bigint(8) # class PreviewCard < ApplicationRecord @@ -54,6 +55,7 @@ class PreviewCard < ApplicationRecord has_many :statuses, through: :preview_cards_statuses has_one :trend, class_name: 'PreviewCardTrend', inverse_of: :preview_card, dependent: :destroy + belongs_to :author_account, class_name: 'Account', optional: true has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false diff --git a/app/models/status.rb b/app/models/status.rb index 9d09fa5fee..baa6578005 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -157,9 +157,9 @@ class Status < ApplicationRecord :status_stat, :tags, :preloadable_poll, - preview_cards_status: [:preview_card], + preview_cards_status: { preview_card: { author_account: [:account_stat, user: :role] } }, account: [:account_stat, user: :role], - active_mentions: { account: :account_stat }, + active_mentions: :account, reblog: [ :application, :tags, @@ -167,11 +167,11 @@ class Status < ApplicationRecord :conversation, :status_stat, :preloadable_poll, - preview_cards_status: [:preview_card], + preview_cards_status: { preview_card: { author_account: [:account_stat, user: :role] } }, account: [:account_stat, user: :role], - active_mentions: { account: :account_stat }, + active_mentions: :account, ], - thread: { account: :account_stat } + thread: :account delegate :domain, to: :account, prefix: true diff --git a/app/serializers/rest/preview_card_serializer.rb b/app/serializers/rest/preview_card_serializer.rb index 039262cd5f..7d4c99c2d1 100644 --- a/app/serializers/rest/preview_card_serializer.rb +++ b/app/serializers/rest/preview_card_serializer.rb @@ -8,6 +8,8 @@ class REST::PreviewCardSerializer < ActiveModel::Serializer :provider_url, :html, :width, :height, :image, :image_description, :embed_url, :blurhash, :published_at + has_one :author_account, serializer: REST::AccountSerializer, if: -> { object.author_account.present? } + def url object.original_url.presence || object.url end diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index 36e866b6ce..900cb9863d 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -147,9 +147,12 @@ class FetchLinkCardService < BaseService return if html.nil? link_details_extractor = LinkDetailsExtractor.new(@url, @html, @html_charset) + provider = PreviewCardProvider.matching_domain(Addressable::URI.parse(link_details_extractor.canonical_url).normalized_host) + linked_account = ResolveAccountService.new.call(link_details_extractor.author_account, suppress_errors: true) if link_details_extractor.author_account.present? && provider&.trendable? @card = PreviewCard.find_or_initialize_by(url: link_details_extractor.canonical_url) if link_details_extractor.canonical_url != @card.url @card.assign_attributes(link_details_extractor.to_preview_card_attributes) + @card.author_account = linked_account @card.save_with_optional_image! unless @card.title.blank? && @card.html.blank? end end diff --git a/db/migrate/20240522041528_add_author_account_id_to_preview_cards.rb b/db/migrate/20240522041528_add_author_account_id_to_preview_cards.rb new file mode 100644 index 0000000000..a6e7a883da --- /dev/null +++ b/db/migrate/20240522041528_add_author_account_id_to_preview_cards.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class AddAuthorAccountIdToPreviewCards < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + safety_assured { add_reference :preview_cards, :author_account, null: true, foreign_key: { to_table: 'accounts', on_delete: :nullify }, index: false } + add_index :preview_cards, :author_account_id, algorithm: :concurrently, where: 'author_account_id IS NOT NULL' + end +end diff --git a/db/schema.rb b/db/schema.rb index ad58604928..3a47522d26 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_10_192043) do +ActiveRecord::Schema[7.1].define(version: 2024_05_22_041528) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -877,6 +877,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_10_192043) do t.integer "link_type" t.datetime "published_at" t.string "image_description", default: "", null: false + t.bigint "author_account_id" + t.index ["author_account_id"], name: "index_preview_cards_on_author_account_id", where: "(author_account_id IS NOT NULL)" t.index ["url"], name: "index_preview_cards_on_url", unique: true end @@ -1352,6 +1354,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_10_192043) do add_foreign_key "polls", "accounts", on_delete: :cascade add_foreign_key "polls", "statuses", on_delete: :cascade add_foreign_key "preview_card_trends", "preview_cards", on_delete: :cascade + add_foreign_key "preview_cards", "accounts", column: "author_account_id", on_delete: :nullify add_foreign_key "report_notes", "accounts", on_delete: :cascade add_foreign_key "report_notes", "reports", on_delete: :cascade add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", name: "fk_bca45b75fd", on_delete: :nullify From 5d7d23999ca0fffc3012d84b89fc9d3e66099115 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 29 May 2024 10:15:06 +0200 Subject: [PATCH 259/658] Fix leaking Elasticsearch connections in Sidekiq processes (#30450) --- lib/mastodon/sidekiq_middleware.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/mastodon/sidekiq_middleware.rb b/lib/mastodon/sidekiq_middleware.rb index 3a747afb63..c5f4d8da35 100644 --- a/lib/mastodon/sidekiq_middleware.rb +++ b/lib/mastodon/sidekiq_middleware.rb @@ -8,6 +8,7 @@ class Mastodon::SidekiqMiddleware rescue Mastodon::HostValidationError # Do not retry rescue => e + clean_up_elasticsearch_connections! limit_backtrace_and_raise(e) ensure clean_up_sockets! @@ -25,6 +26,32 @@ class Mastodon::SidekiqMiddleware clean_up_statsd_socket! end + # This is a hack to immediately free up unused Elasticsearch connections. + # + # Indeed, Chewy creates one `Elasticsearch::Client` instance per thread, + # and each such client manages its long-lasting connection to + # Elasticsearch. + # + # As far as I know, neither `chewy`, `elasticsearch-transport` or even + # `faraday` provide a reliable way to immediately close a connection, and + # rely on the underlying object to be garbage-collected instead. + # + # Furthermore, `sidekiq` creates a new thread each time a job throws an + # exception, meaning that each failure will create a new connection, and + # the old one will only be closed on full garbage collection. + def clean_up_elasticsearch_connections! + return unless Chewy.enabled? && Chewy.current[:chewy_client].present? + + Chewy.client.transport.transport.connections.each do |connection| + # NOTE: This bit of code is tailored for the HTTPClient Faraday adapter + connection.connection.app.instance_variable_get(:@client)&.reset_all + end + + Chewy.current.delete(:chewy_client) + rescue + nil + end + def clean_up_redis_socket! RedisConfiguration.pool.checkin if Thread.current[:redis] Thread.current[:redis] = nil From 36fe8f85667717e78740a9fed3c2bf116a96da1e Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 29 May 2024 11:19:17 +0200 Subject: [PATCH 260/658] Change `ids` param to `id` in `/api/v1/statuses` and `/api/v1/accounts` for consistency (#30465) --- app/controllers/api/v1/accounts_controller.rb | 4 ++-- app/controllers/api/v1/statuses_controller.rb | 4 ++-- spec/requests/api/v1/accounts_spec.rb | 4 ++-- spec/requests/api/v1/statuses_spec.rb | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index be7b302d3b..84b604b305 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -106,11 +106,11 @@ class Api::V1::AccountsController < Api::BaseController end def account_ids - Array(accounts_params[:ids]).uniq.map(&:to_i) + Array(accounts_params[:id]).uniq.map(&:to_i) end def accounts_params - params.permit(ids: []) + params.permit(id: []) end def account_params diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 5f7e66617d..cca3865f62 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -141,11 +141,11 @@ class Api::V1::StatusesController < Api::BaseController end def status_ids - Array(statuses_params[:ids]).uniq.map(&:to_i) + Array(statuses_params[:id]).uniq.map(&:to_i) end def statuses_params - params.permit(ids: []) + params.permit(id: []) end def status_params diff --git a/spec/requests/api/v1/accounts_spec.rb b/spec/requests/api/v1/accounts_spec.rb index 55f8e1c6fa..3d9eb65019 100644 --- a/spec/requests/api/v1/accounts_spec.rb +++ b/spec/requests/api/v1/accounts_spec.rb @@ -8,13 +8,13 @@ describe '/api/v1/accounts' do let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - describe 'GET /api/v1/accounts?ids[]=:id' do + describe 'GET /api/v1/accounts?id[]=:id' do let(:account) { Fabricate(:account) } let(:other_account) { Fabricate(:account) } let(:scopes) { 'read:accounts' } it 'returns expected response' do - get '/api/v1/accounts', headers: headers, params: { ids: [account.id, other_account.id, 123_123] } + get '/api/v1/accounts', headers: headers, params: { id: [account.id, other_account.id, 123_123] } expect(response).to have_http_status(200) expect(body_as_json).to contain_exactly( diff --git a/spec/requests/api/v1/statuses_spec.rb b/spec/requests/api/v1/statuses_spec.rb index 0b2d1f90cf..694861fb1c 100644 --- a/spec/requests/api/v1/statuses_spec.rb +++ b/spec/requests/api/v1/statuses_spec.rb @@ -9,13 +9,13 @@ describe '/api/v1/statuses' do let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: client_app, scopes: scopes) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - describe 'GET /api/v1/statuses?ids[]=:id' do + describe 'GET /api/v1/statuses?id[]=:id' do let(:status) { Fabricate(:status) } let(:other_status) { Fabricate(:status) } let(:scopes) { 'read:statuses' } it 'returns expected response' do - get '/api/v1/statuses', headers: headers, params: { ids: [status.id, other_status.id, 123_123] } + get '/api/v1/statuses', headers: headers, params: { id: [status.id, other_status.id, 123_123] } expect(response).to have_http_status(200) expect(body_as_json).to contain_exactly( From 41729313e23bc4305cf0e7536d49af2490477c32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 11:34:36 +0200 Subject: [PATCH 261/658] chore(deps): update dependency faker to v3.4.1 (#30463) 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 934d41334d..5c480c525c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -231,7 +231,7 @@ GEM tzinfo excon (0.110.0) fabrication (2.31.0) - faker (3.3.1) + faker (3.4.1) i18n (>= 1.8.11, < 2) faraday (1.10.3) faraday-em_http (~> 1.0) From 6eea83211c049e416d24f394039a74bc60450cd7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 13:12:23 +0200 Subject: [PATCH 262/658] New Crowdin Translations (automated) (#30464) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ca.json | 1 + app/javascript/mastodon/locales/es-AR.json | 1 + app/javascript/mastodon/locales/fi.json | 1 + app/javascript/mastodon/locales/gl.json | 1 + app/javascript/mastodon/locales/it.json | 1 + app/javascript/mastodon/locales/ko.json | 1 + app/javascript/mastodon/locales/pl.json | 1 + app/javascript/mastodon/locales/pt-BR.json | 1 + app/javascript/mastodon/locales/pt-PT.json | 1 + app/javascript/mastodon/locales/sl.json | 1 + app/javascript/mastodon/locales/vi.json | 1 + app/javascript/mastodon/locales/zh-CN.json | 1 + app/javascript/mastodon/locales/zh-TW.json | 1 + 13 files changed, 13 insertions(+) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index ea67d217da..68429b093c 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Mostra el perfil de totes maneres", "limited_account_hint.title": "Aquest perfil l'han amagat els moderadors de {domain}.", "link_preview.author": "Per {name}", + "link_preview.more_from_author": "Més de {name}", "lists.account.add": "Afegeix a la llista", "lists.account.remove": "Elimina de la llista", "lists.delete": "Elimina la llista", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 2d42b3e949..4c30bfa25f 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Mostrar perfil de todos modos", "limited_account_hint.title": "Este perfil fue ocultado por los moderadores de {domain}.", "link_preview.author": "Por {name}", + "link_preview.more_from_author": "Más de {name}", "lists.account.add": "Agregar a lista", "lists.account.remove": "Quitar de lista", "lists.delete": "Eliminar lista", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index bae714b1d2..6c2162e52c 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Näytä profiili joka tapauksessa", "limited_account_hint.title": "Palvelimen {domain} valvojat ovat piilottaneet tämän käyttäjätilin.", "link_preview.author": "Julkaissut {name}", + "link_preview.more_from_author": "Lisää käyttäjältä {name}", "lists.account.add": "Lisää listalle", "lists.account.remove": "Poista listalta", "lists.delete": "Poista lista", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 98cc313948..0847b8bf0d 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Mostrar perfil igualmente", "limited_account_hint.title": "Este perfil foi agochado pola moderación de {domain}.", "link_preview.author": "Por {name}", + "link_preview.more_from_author": "Máis de {name}", "lists.account.add": "Engadir á listaxe", "lists.account.remove": "Eliminar da listaxe", "lists.delete": "Eliminar listaxe", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 8ab5db1b17..f66497e0a7 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Mostra comunque il profilo", "limited_account_hint.title": "Questo profilo è stato nascosto dai moderatori di {domain}.", "link_preview.author": "Di {name}", + "link_preview.more_from_author": "Altro da {name}", "lists.account.add": "Aggiungi all'elenco", "lists.account.remove": "Rimuovi dall'elenco", "lists.delete": "Elimina elenco", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index b340261479..7cd74fa501 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "그래도 프로필 보기", "limited_account_hint.title": "이 프로필은 {domain}의 중재자에 의해 숨겨진 상태입니다.", "link_preview.author": "{name}", + "link_preview.more_from_author": "{name} 더 둘러보기", "lists.account.add": "리스트에 추가", "lists.account.remove": "리스트에서 제거", "lists.delete": "리스트 삭제", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index b763f740a2..6f67e8f74f 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Pokaż profil mimo to", "limited_account_hint.title": "Ten profil został ukryty przez moderatorów {domain}.", "link_preview.author": "{name}", + "link_preview.more_from_author": "Więcej od {name}", "lists.account.add": "Dodaj do listy", "lists.account.remove": "Usunąć z listy", "lists.delete": "Usuń listę", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index b11daeaaa7..3c8f3cf416 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Exibir perfil mesmo assim", "limited_account_hint.title": "Este perfil foi ocultado pelos moderadores do {domain}.", "link_preview.author": "Por {name}", + "link_preview.more_from_author": "Mais de {name}", "lists.account.add": "Adicionar à lista", "lists.account.remove": "Remover da lista", "lists.delete": "Excluir lista", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 70903065da..c389d4f4fc 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Exibir perfil mesmo assim", "limited_account_hint.title": "Este perfil foi ocultado pelos moderadores de {domain}.", "link_preview.author": "Por {name}", + "link_preview.more_from_author": "Mais de {name}", "lists.account.add": "Adicionar à lista", "lists.account.remove": "Remover da lista", "lists.delete": "Eliminar lista", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 7806abc6b5..a8cce3202c 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Vseeno pokaži profil", "limited_account_hint.title": "Profil so moderatorji strežnika {domain} skrili.", "link_preview.author": "Avtor_ica {name}", + "link_preview.more_from_author": "Več od {name}", "lists.account.add": "Dodaj na seznam", "lists.account.remove": "Odstrani s seznama", "lists.delete": "Izbriši seznam", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 102f1c3b4b..56b2f7e52c 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Vẫn cứ xem", "limited_account_hint.title": "Người này đã bị ẩn bởi quản trị viên của {domain}.", "link_preview.author": "Bởi {name}", + "link_preview.more_from_author": "Thêm từ {name}", "lists.account.add": "Thêm vào danh sách", "lists.account.remove": "Xóa khỏi danh sách", "lists.delete": "Xóa danh sách", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index ab6fe0bd70..0f8bcae6f8 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "仍要显示个人资料", "limited_account_hint.title": "此账号资料已被 {domain} 管理员隐藏。", "link_preview.author": "由 {name}", + "link_preview.more_from_author": "查看 {name} 的更多内容", "lists.account.add": "添加到列表", "lists.account.remove": "从列表中移除", "lists.delete": "删除列表", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index f00d62c076..1d20034db8 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "一律顯示個人檔案", "limited_account_hint.title": "此個人檔案已被 {domain} 的管理員隱藏。", "link_preview.author": "來自 {name}", + "link_preview.more_from_author": "來自 {name} 之更多內容", "lists.account.add": "新增至列表", "lists.account.remove": "自列表中移除", "lists.delete": "刪除列表", From d20a5c3ec9ed40a991245fe32d0acb6187dd48c4 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Wed, 29 May 2024 16:00:05 +0200 Subject: [PATCH 263/658] Fix: remove broken OAuth Application vacuuming & throttle OAuth Application registrations (#30316) Co-authored-by: Claire --- app/lib/vacuum/applications_vacuum.rb | 10 ---- app/workers/scheduler/vacuum_scheduler.rb | 5 -- config/initializers/rack_attack.rb | 4 ++ spec/config/initializers/rack/attack_spec.rb | 18 ++++++++ spec/lib/vacuum/applications_vacuum_spec.rb | 48 -------------------- 5 files changed, 22 insertions(+), 63 deletions(-) delete mode 100644 app/lib/vacuum/applications_vacuum.rb delete mode 100644 spec/lib/vacuum/applications_vacuum_spec.rb diff --git a/app/lib/vacuum/applications_vacuum.rb b/app/lib/vacuum/applications_vacuum.rb deleted file mode 100644 index ba88655f16..0000000000 --- a/app/lib/vacuum/applications_vacuum.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -class Vacuum::ApplicationsVacuum - def perform - Doorkeeper::Application.where(owner_id: nil) - .where.missing(:created_users, :access_tokens, :access_grants) - .where(created_at: ...1.day.ago) - .in_batches.delete_all - end -end diff --git a/app/workers/scheduler/vacuum_scheduler.rb b/app/workers/scheduler/vacuum_scheduler.rb index 1c9a2aabe3..c22d6f5f80 100644 --- a/app/workers/scheduler/vacuum_scheduler.rb +++ b/app/workers/scheduler/vacuum_scheduler.rb @@ -22,7 +22,6 @@ class Scheduler::VacuumScheduler preview_cards_vacuum, backups_vacuum, access_tokens_vacuum, - applications_vacuum, feeds_vacuum, imports_vacuum, ] @@ -56,10 +55,6 @@ class Scheduler::VacuumScheduler Vacuum::ImportsVacuum.new end - def applications_vacuum - Vacuum::ApplicationsVacuum.new - end - def content_retention_policy ContentRetentionPolicy.current end diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index fa1bdca544..1757ce5df1 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -105,6 +105,10 @@ class Rack::Attack req.authenticated_user_id if (req.post? && req.path.match?(API_DELETE_REBLOG_REGEX)) || (req.delete? && req.path.match?(API_DELETE_STATUS_REGEX)) end + throttle('throttle_oauth_application_registrations/ip', limit: 5, period: 10.minutes) do |req| + req.throttleable_remote_ip if req.post? && req.path == '/api/v1/apps' + end + throttle('throttle_sign_up_attempts/ip', limit: 25, period: 5.minutes) do |req| req.throttleable_remote_ip if req.post? && req.path_matches?('/auth') end diff --git a/spec/config/initializers/rack/attack_spec.rb b/spec/config/initializers/rack/attack_spec.rb index e25b7dfde9..0a388c2f41 100644 --- a/spec/config/initializers/rack/attack_spec.rb +++ b/spec/config/initializers/rack/attack_spec.rb @@ -131,4 +131,22 @@ describe Rack::Attack, type: :request do it_behaves_like 'throttled endpoint' end end + + describe 'throttle excessive oauth application registration requests by IP address' do + let(:throttle) { 'throttle_oauth_application_registrations/ip' } + let(:limit) { 5 } + let(:period) { 10.minutes } + let(:path) { '/api/v1/apps' } + let(:params) do + { + client_name: 'Throttle Test', + redirect_uris: 'urn:ietf:wg:oauth:2.0:oob', + scopes: 'read', + } + end + + let(:request) { -> { post path, params: params, headers: { 'REMOTE_ADDR' => remote_ip } } } + + it_behaves_like 'throttled endpoint' + end end diff --git a/spec/lib/vacuum/applications_vacuum_spec.rb b/spec/lib/vacuum/applications_vacuum_spec.rb deleted file mode 100644 index df5c860602..0000000000 --- a/spec/lib/vacuum/applications_vacuum_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::ApplicationsVacuum do - subject { described_class.new } - - describe '#perform' do - let!(:app_with_token) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app_with_grant) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app_with_signup) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app_with_owner) { Fabricate(:application, created_at: 1.month.ago, owner: Fabricate(:user)) } - let!(:unused_app) { Fabricate(:application, created_at: 1.month.ago) } - let!(:recent_app) { Fabricate(:application, created_at: 1.hour.ago) } - - before do - Fabricate(:access_token, application: app_with_token) - Fabricate(:access_grant, application: app_with_grant) - Fabricate(:user, created_by_application: app_with_signup) - - subject.perform - end - - it 'does not delete applications with valid access tokens' do - expect { app_with_token.reload }.to_not raise_error - end - - it 'does not delete applications with valid access grants' do - expect { app_with_grant.reload }.to_not raise_error - end - - it 'does not delete applications that were used to create users' do - expect { app_with_signup.reload }.to_not raise_error - end - - it 'does not delete owned applications' do - expect { app_with_owner.reload }.to_not raise_error - end - - it 'does not delete applications registered less than a day ago' do - expect { recent_app.reload }.to_not raise_error - end - - it 'deletes unused applications' do - expect { unused_app.reload }.to raise_error ActiveRecord::RecordNotFound - end - end -end From 6b4c182806b141d432f4e25a194e15aacb421128 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 27 May 2024 11:00:40 +0200 Subject: [PATCH 264/658] [Glitch] Fix `createDataLoadingThunk` to allow actions without arguments Port 6a75e1c8c82a1625867ea69be3d0c55697448f4e to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/store/typed_functions.ts | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/app/javascript/flavours/glitch/store/typed_functions.ts b/app/javascript/flavours/glitch/store/typed_functions.ts index 0392f373c0..dae37e6225 100644 --- a/app/javascript/flavours/glitch/store/typed_functions.ts +++ b/app/javascript/flavours/glitch/store/typed_functions.ts @@ -89,21 +89,17 @@ type OnData = ( }, ) => ReturnedData | DiscardLoadData | Promise; +type ArgsType = Record | undefined; + // Overload when there is no `onData` method, the payload is the `onData` result -export function createDataLoadingThunk< - LoadDataResult, - Args extends Record, ->( +export function createDataLoadingThunk( name: string, loadData: (args: Args) => Promise, thunkOptions?: AppThunkOptions, ): ReturnType>; // Overload when the `onData` method returns discardLoadDataInPayload, then the payload is empty -export function createDataLoadingThunk< - LoadDataResult, - Args extends Record, ->( +export function createDataLoadingThunk( name: string, loadData: (args: Args) => Promise, onDataOrThunkOptions?: @@ -113,10 +109,7 @@ export function createDataLoadingThunk< ): ReturnType>; // Overload when the `onData` method returns nothing, then the mayload is the `onData` result -export function createDataLoadingThunk< - LoadDataResult, - Args extends Record, ->( +export function createDataLoadingThunk( name: string, loadData: (args: Args) => Promise, onDataOrThunkOptions?: AppThunkOptions | OnData, @@ -126,7 +119,7 @@ export function createDataLoadingThunk< // Overload when there is an `onData` method returning something export function createDataLoadingThunk< LoadDataResult, - Args extends Record, + Args extends ArgsType, Returned, >( name: string, @@ -162,7 +155,7 @@ export function createDataLoadingThunk< */ export function createDataLoadingThunk< LoadDataResult, - Args extends Record, + Args extends ArgsType, Returned, >( name: string, From 2e3d6e451faeb8ee248a309c294f797586551bc6 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Mon, 27 May 2024 11:24:59 +0200 Subject: [PATCH 265/658] [Glitch] Enable stricter Typescript options Port 3750e8050cb4a5707e76dfb8f49687cc0984f67f to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/components/animated_number.tsx | 5 +++-- .../flavours/glitch/components/hashtag_bar.tsx | 7 +++++-- .../flavours/glitch/components/short_number.tsx | 2 +- .../flavours/glitch/entrypoints/public.tsx | 12 ++++++------ .../glitch/entrypoints/remote_interaction_helper.ts | 9 ++++++++- .../glitch/features/emoji/emoji_mart_data_light.ts | 5 ++++- .../features/emoji/emoji_unicode_mapping_light.ts | 5 ++++- .../flavours/glitch/store/middlewares/sounds.ts | 5 +++-- 8 files changed, 34 insertions(+), 16 deletions(-) diff --git a/app/javascript/flavours/glitch/components/animated_number.tsx b/app/javascript/flavours/glitch/components/animated_number.tsx index 05a7e01898..e784d445d4 100644 --- a/app/javascript/flavours/glitch/components/animated_number.tsx +++ b/app/javascript/flavours/glitch/components/animated_number.tsx @@ -63,8 +63,9 @@ export const AnimatedNumber: React.FC = ({ value, obfuscate }) => { 0 ? 'absolute' : 'static', - transform: `translateY(${style.y * 100}%)`, + position: + direction * (style.y ?? 0) > 0 ? 'absolute' : 'static', + transform: `translateY(${(style.y ?? 0) * 100}%)`, }} > {obfuscate ? ( diff --git a/app/javascript/flavours/glitch/components/hashtag_bar.tsx b/app/javascript/flavours/glitch/components/hashtag_bar.tsx index ed5de7d3a5..1642ba6504 100644 --- a/app/javascript/flavours/glitch/components/hashtag_bar.tsx +++ b/app/javascript/flavours/glitch/components/hashtag_bar.tsx @@ -52,7 +52,10 @@ function uniqueHashtagsWithCaseHandling(hashtags: string[]) { ); return Object.values(groups).map((tags) => { - if (tags.length === 1) return tags[0]; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we know that the array has at least one element + const firstTag = tags[0]!; + + if (tags.length === 1) return firstTag; // The best match is the one where we have the less difference between upper and lower case letter count const best = minBy(tags, (tag) => { @@ -66,7 +69,7 @@ function uniqueHashtagsWithCaseHandling(hashtags: string[]) { return Math.abs(lowerCase - upperCase); }); - return best ?? tags[0]; + return best ?? firstTag; }); } diff --git a/app/javascript/flavours/glitch/components/short_number.tsx b/app/javascript/flavours/glitch/components/short_number.tsx index 74c3c5d75e..a0b523aaad 100644 --- a/app/javascript/flavours/glitch/components/short_number.tsx +++ b/app/javascript/flavours/glitch/components/short_number.tsx @@ -48,7 +48,7 @@ const ShortNumberCounter: React.FC = ({ value }) => { const count = ( ); diff --git a/app/javascript/flavours/glitch/entrypoints/public.tsx b/app/javascript/flavours/glitch/entrypoints/public.tsx index ab453ef119..5a8d5e08cb 100644 --- a/app/javascript/flavours/glitch/entrypoints/public.tsx +++ b/app/javascript/flavours/glitch/entrypoints/public.tsx @@ -65,7 +65,7 @@ window.addEventListener('message', (e) => { { type: 'setHeight', id: data.id, - height: document.getElementsByTagName('html')[0].scrollHeight, + height: document.getElementsByTagName('html')[0]?.scrollHeight, }, '*', ); @@ -135,7 +135,7 @@ function loaded() { ); }; const todayFormat = new IntlMessageFormat( - localeData['relative_format.today'] || 'Today at {time}', + localeData['relative_format.today'] ?? 'Today at {time}', locale, ); @@ -288,13 +288,13 @@ function loaded() { if (statusEl.dataset.spoiler === 'expanded') { statusEl.dataset.spoiler = 'folded'; this.textContent = new IntlMessageFormat( - localeData['status.show_more'] || 'Show more', + localeData['status.show_more'] ?? 'Show more', locale, ).format() as string; } else { statusEl.dataset.spoiler = 'expanded'; this.textContent = new IntlMessageFormat( - localeData['status.show_less'] || 'Show less', + localeData['status.show_less'] ?? 'Show less', locale, ).format() as string; } @@ -316,8 +316,8 @@ function loaded() { const message = statusEl.dataset.spoiler === 'expanded' - ? localeData['status.show_less'] || 'Show less' - : localeData['status.show_more'] || 'Show more'; + ? localeData['status.show_less'] ?? 'Show less' + : localeData['status.show_more'] ?? 'Show more'; spoilerLink.textContent = new IntlMessageFormat( message, locale, diff --git a/app/javascript/flavours/glitch/entrypoints/remote_interaction_helper.ts b/app/javascript/flavours/glitch/entrypoints/remote_interaction_helper.ts index 8cb476f483..3bfc1fc139 100644 --- a/app/javascript/flavours/glitch/entrypoints/remote_interaction_helper.ts +++ b/app/javascript/flavours/glitch/entrypoints/remote_interaction_helper.ts @@ -67,7 +67,9 @@ const fetchInteractionURLFailure = () => { ); }; -const isValidDomain = (value: string) => { +const isValidDomain = (value: unknown) => { + if (typeof value !== 'string') return false; + const url = new URL('https:///path'); url.hostname = value; return url.hostname === value; @@ -124,6 +126,11 @@ const fromAcct = (acct: string) => { const domain = segments[1]; const fallbackTemplate = `https://${domain}/authorize_interaction?uri={uri}`; + if (!domain) { + fetchInteractionURLFailure(); + return; + } + axios .get(`https://${domain}/.well-known/webfinger`, { params: { resource: `acct:${acct}` }, diff --git a/app/javascript/flavours/glitch/features/emoji/emoji_mart_data_light.ts b/app/javascript/flavours/glitch/features/emoji/emoji_mart_data_light.ts index ffca1f8b06..806a3f8927 100644 --- a/app/javascript/flavours/glitch/features/emoji/emoji_mart_data_light.ts +++ b/app/javascript/flavours/glitch/features/emoji/emoji_mart_data_light.ts @@ -29,7 +29,10 @@ const emojis: Emojis = {}; // decompress Object.keys(shortCodesToEmojiData).forEach((shortCode) => { - const [_filenameData, searchData] = shortCodesToEmojiData[shortCode]; + const emojiData = shortCodesToEmojiData[shortCode]; + if (!emojiData) return; + + const [_filenameData, searchData] = emojiData; const [native, short_names, search, unified] = searchData; emojis[shortCode] = { diff --git a/app/javascript/flavours/glitch/features/emoji/emoji_unicode_mapping_light.ts b/app/javascript/flavours/glitch/features/emoji/emoji_unicode_mapping_light.ts index 191419496f..d116c6c62c 100644 --- a/app/javascript/flavours/glitch/features/emoji/emoji_unicode_mapping_light.ts +++ b/app/javascript/flavours/glitch/features/emoji/emoji_unicode_mapping_light.ts @@ -46,7 +46,10 @@ function processEmojiMapData( Object.keys(shortCodesToEmojiData).forEach( (shortCode: ShortCodesToEmojiDataKey) => { if (shortCode === undefined) return; - const [filenameData, _searchData] = shortCodesToEmojiData[shortCode]; + + const emojiData = shortCodesToEmojiData[shortCode]; + if (!emojiData) return; + const [filenameData, _searchData] = emojiData; filenameData.forEach((emojiMapData) => { processEmojiMapData(emojiMapData, shortCode); }); diff --git a/app/javascript/flavours/glitch/store/middlewares/sounds.ts b/app/javascript/flavours/glitch/store/middlewares/sounds.ts index ab04f6c94b..ced4d910bf 100644 --- a/app/javascript/flavours/glitch/store/middlewares/sounds.ts +++ b/app/javascript/flavours/glitch/store/middlewares/sounds.ts @@ -74,8 +74,9 @@ export const soundsMiddleware = (): Middleware< if (isActionWithMetaSound(action)) { const sound = action.meta.sound; - if (sound && Object.hasOwn(soundCache, sound)) { - play(soundCache[sound]); + if (sound) { + const s = soundCache[sound]; + if (s) play(s); } } From 4069fae10d548ddfb7d030890224b868982f57fd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 29 May 2024 01:34:33 +0200 Subject: [PATCH 266/658] [Glitch] Add support for `fediverse:creator` OpenGraph tag Port 128987ededcbcdf73529d98a4f11c747b2bbe892 to glitch-soc Signed-off-by: Claire --- .../features/status/components/card.jsx | 31 ++++++++++--- .../flavours/glitch/styles/components.scss | 43 +++++++++++++++++++ 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/app/javascript/flavours/glitch/features/status/components/card.jsx b/app/javascript/flavours/glitch/features/status/components/card.jsx index 4c535b0a46..c6094d0beb 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.jsx +++ b/app/javascript/flavours/glitch/features/status/components/card.jsx @@ -11,8 +11,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import DescriptionIcon from '@/material-icons/400-24px/description-fill.svg?react'; import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react'; import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; +import { Avatar } from 'flavours/glitch/components/avatar'; import { Blurhash } from 'flavours/glitch/components/blurhash'; import { Icon } from 'flavours/glitch/components/icon'; +import { Permalink } from 'flavours/glitch/components/permalink'; import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp'; import { useBlurhash } from 'flavours/glitch/initial_state'; import { decode as decodeIDNA } from 'flavours/glitch/utils/idna'; @@ -46,6 +48,20 @@ const addAutoPlay = html => { return html; }; +const MoreFromAuthor = ({ author }) => ( +
+ + + + + {author.get('display_name')} }} /> +
+); + +MoreFromAuthor.propTypes = { + author: ImmutablePropTypes.map, +}; + export default class Card extends PureComponent { static propTypes = { @@ -126,6 +142,7 @@ export default class Card extends PureComponent { const interactive = card.get('type') === 'video'; const language = card.get('language') || ''; const largeImage = (card.get('image')?.length > 0 && card.get('width') > card.get('height')) || interactive; + const showAuthor = !!card.get('author_account'); const description = (
@@ -136,7 +153,7 @@ export default class Card extends PureComponent { {card.get('title')} - {card.get('author_name').length > 0 ? {card.get('author_name')} }} /> : {card.get('description')}} + {!showAuthor && (card.get('author_name').length > 0 ? {card.get('author_name')} }} /> : {card.get('description')})}
); @@ -225,10 +242,14 @@ export default class Card extends PureComponent { } return ( - - {embed} - {description} - + <> + + {embed} + {description} + + + {showAuthor && } + ); } diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 07b18b2936..424b65a3f1 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -4133,6 +4133,10 @@ input.glitch-setting-text { border: 1px solid var(--background-border-color); border-radius: 8px; + &.bottomless { + border-radius: 8px 8px 0 0; + } + &__actions { bottom: 0; inset-inline-start: 0; @@ -10811,3 +10815,42 @@ noscript { } } } + +.more-from-author { + font-size: 14px; + color: $darker-text-color; + background: var(--surface-background-color); + border: 1px solid var(--background-border-color); + border-top: 0; + border-radius: 0 0 8px 8px; + padding: 15px; + display: flex; + align-items: center; + gap: 8px; + + .logo { + height: 16px; + color: $darker-text-color; + } + + & > span { + display: flex; + align-items: center; + gap: 8px; + } + + a { + display: inline-flex; + align-items: center; + gap: 4px; + font-weight: 500; + color: $primary-text-color; + text-decoration: none; + + &:hover, + &:focus, + &:active { + color: $highlight-text-color; + } + } +} From 3ea4275ae3b7dc2b75e7a2db09b13576b49cec7a Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 30 May 2024 14:03:13 +0200 Subject: [PATCH 267/658] Merge pull request from GHSA-5fq7-3p3j-9vrf --- app/services/notify_service.rb | 20 ++++++++++++-------- spec/services/notify_service_spec.rb | 13 +++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index e56562c0a5..1f01c2d48e 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -147,6 +147,9 @@ class NotifyService < BaseService end def statuses_that_mention_sender + # This queries private mentions from the recipient to the sender up in the thread. + # This allows up to 100 messages that do not match in the thread, allowing conversations + # involving multiple people. Status.count_by_sql([<<-SQL.squish, id: @notification.target_status.in_reply_to_id, recipient_id: @recipient.id, sender_id: @sender.id, depth_limit: 100]) WITH RECURSIVE ancestors(id, in_reply_to_id, mention_id, path, depth) AS ( SELECT s.id, s.in_reply_to_id, m.id, ARRAY[s.id], 0 @@ -154,16 +157,17 @@ class NotifyService < BaseService LEFT JOIN mentions m ON m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id WHERE s.id = :id UNION ALL - SELECT s.id, s.in_reply_to_id, m.id, st.path || s.id, st.depth + 1 - FROM ancestors st - JOIN statuses s ON s.id = st.in_reply_to_id - LEFT JOIN mentions m ON m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id - WHERE st.mention_id IS NULL AND NOT s.id = ANY(path) AND st.depth < :depth_limit + SELECT s.id, s.in_reply_to_id, m.id, ancestors.path || s.id, ancestors.depth + 1 + FROM ancestors + JOIN statuses s ON s.id = ancestors.in_reply_to_id + /* early exit if we already have a mention matching our requirements */ + LEFT JOIN mentions m ON m.silent = FALSE AND m.account_id = :sender_id AND m.status_id = s.id AND s.account_id = :recipient_id + WHERE ancestors.mention_id IS NULL AND NOT s.id = ANY(path) AND ancestors.depth < :depth_limit ) SELECT COUNT(*) - FROM ancestors st - JOIN statuses s ON s.id = st.id - WHERE st.mention_id IS NOT NULL AND s.visibility = 3 + FROM ancestors + JOIN statuses s ON s.id = ancestors.id + WHERE ancestors.mention_id IS NOT NULL AND s.account_id = :recipient_id AND s.visibility = 3 SQL end end diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index 514f634d7f..6064d2b050 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -309,6 +309,19 @@ RSpec.describe NotifyService do expect(subject.filter?).to be false end end + + context 'when the sender is mentioned in an unrelated message chain' do + before do + original_status = Fabricate(:status, visibility: :direct) + intermediary_status = Fabricate(:status, visibility: :direct, thread: original_status) + notification.target_status.update(thread: intermediary_status) + Fabricate(:mention, status: original_status, account: notification.from_account) + end + + it 'returns true' do + expect(subject.filter?).to be true + end + end end end end From 16249946aea0db8a74748909d65c94742482dcb7 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 30 May 2024 14:14:04 +0200 Subject: [PATCH 268/658] Merge pull request from GHSA-q3rg-xx5v-4mxh --- config/initializers/rack_attack.rb | 10 ++++++- spec/config/initializers/rack/attack_spec.rb | 31 ++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 1757ce5df1..034fb7444d 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -30,13 +30,17 @@ class Rack::Attack end def authenticated_user_id - authenticated_token&.resource_owner_id + authenticated_token&.resource_owner_id || warden_user_id end def authenticated_token_id authenticated_token&.id end + def warden_user_id + @env['warden']&.user&.id + end + def unauthenticated? !authenticated_user_id end @@ -141,6 +145,10 @@ class Rack::Attack req.session[:attempt_user_id] || req.params.dig('user', 'email').presence if req.post? && req.path_matches?('/auth/sign_in') end + throttle('throttle_password_change/account', limit: 10, period: 10.minutes) do |req| + req.authenticated_user_id if req.put? || (req.patch? && req.path_matches?('/auth')) + end + self.throttled_responder = lambda do |request| now = Time.now.utc match_data = request.env['rack.attack.match_data'] diff --git a/spec/config/initializers/rack/attack_spec.rb b/spec/config/initializers/rack/attack_spec.rb index 0a388c2f41..19de480898 100644 --- a/spec/config/initializers/rack/attack_spec.rb +++ b/spec/config/initializers/rack/attack_spec.rb @@ -56,7 +56,7 @@ describe Rack::Attack, type: :request do end def throttle_count - described_class.cache.read("#{counter_prefix}:#{throttle}:#{remote_ip}") || 0 + described_class.cache.read("#{counter_prefix}:#{throttle}:#{discriminator}") || 0 end def counter_prefix @@ -64,11 +64,12 @@ describe Rack::Attack, type: :request do end def increment_counter - described_class.cache.count("#{throttle}:#{remote_ip}", period) + described_class.cache.count("#{throttle}:#{discriminator}", period) end end let(:remote_ip) { '1.2.3.5' } + let(:discriminator) { remote_ip } describe 'throttle excessive sign-up requests by IP address' do context 'when accessed through the website' do @@ -149,4 +150,30 @@ describe Rack::Attack, type: :request do it_behaves_like 'throttled endpoint' end + + describe 'throttle excessive password change requests by account' do + let(:user) { Fabricate(:user, email: 'user@host.example') } + let(:throttle) { 'throttle_password_change/account' } + let(:limit) { 10 } + let(:period) { 10.minutes } + let(:request) { -> { put path, headers: { 'REMOTE_ADDR' => remote_ip } } } + let(:path) { '/auth' } + let(:discriminator) { user.id } + + before do + sign_in user, scope: :user + + # Unfortunately, devise's `sign_in` helper causes the `session` to be + # loaded in the next request regardless of whether it's actually accessed + # by the client code. + # + # So, we make an extra query to clear issue a session cookie instead. + # + # A less resource-intensive way to deal with that would be to generate the + # session cookie manually, but this seems pretty involved. + get '/' + end + + it_behaves_like 'throttled endpoint' + end end From 3fa0dd0b88bae1aeb505195044951eb9eebe90f1 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 30 May 2024 14:24:29 +0200 Subject: [PATCH 269/658] Merge pull request from GHSA-c2r5-cfqr-c553 * Add hardening monkey-patch to prevent IP spoofing on misconfigured installations * Remove rack-attack safelist --- config/application.rb | 1 + config/initializers/rack_attack.rb | 4 -- lib/action_dispatch/remote_ip_extensions.rb | 72 +++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 lib/action_dispatch/remote_ip_extensions.rb diff --git a/config/application.rb b/config/application.rb index 07b50ca036..6d6e91a5cc 100644 --- a/config/application.rb +++ b/config/application.rb @@ -48,6 +48,7 @@ require_relative '../lib/chewy/strategy/bypass_with_warning' require_relative '../lib/webpacker/manifest_extensions' require_relative '../lib/webpacker/helper_extensions' require_relative '../lib/rails/engine_extensions' +require_relative '../lib/action_dispatch/remote_ip_extensions' require_relative '../lib/active_record/database_tasks_extensions' require_relative '../lib/active_record/batches' require_relative '../lib/simple_navigation/item_extensions' diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 034fb7444d..b3739429e8 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -62,10 +62,6 @@ class Rack::Attack end end - Rack::Attack.safelist('allow from localhost') do |req| - req.remote_ip == '127.0.0.1' || req.remote_ip == '::1' - end - Rack::Attack.blocklist('deny from blocklist') do |req| IpBlock.blocked?(req.remote_ip) end diff --git a/lib/action_dispatch/remote_ip_extensions.rb b/lib/action_dispatch/remote_ip_extensions.rb new file mode 100644 index 0000000000..e5c48bf3c5 --- /dev/null +++ b/lib/action_dispatch/remote_ip_extensions.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +# Mastodon is not made to be directly accessed without a reverse proxy. +# This monkey-patch prevents remote IP address spoofing when being accessed +# directly. +# +# See PR: https://github.com/rails/rails/pull/51610 + +# In addition to the PR above, it also raises an error if a request with +# `X-Forwarded-For` or `Client-Ip` comes directly from a client without +# going through a trusted proxy. + +# rubocop:disable all -- This is a mostly vendored file + +module ActionDispatch + class RemoteIp + module GetIpExtensions + def calculate_ip + # Set by the Rack web server, this is a single value. + remote_addr = ips_from(@req.remote_addr).last + + # Could be a CSV list and/or repeated headers that were concatenated. + client_ips = ips_from(@req.client_ip).reverse! + forwarded_ips = ips_from(@req.x_forwarded_for).reverse! + + # `Client-Ip` and `X-Forwarded-For` should not, generally, both be set. If they + # are both set, it means that either: + # + # 1) This request passed through two proxies with incompatible IP header + # conventions. + # + # 2) The client passed one of `Client-Ip` or `X-Forwarded-For` + # (whichever the proxy servers weren't using) themselves. + # + # Either way, there is no way for us to determine which header is the right one + # after the fact. Since we have no idea, if we are concerned about IP spoofing + # we need to give up and explode. (If you're not concerned about IP spoofing you + # can turn the `ip_spoofing_check` option off.) + should_check_ip = @check_ip && client_ips.last && forwarded_ips.last + if should_check_ip && !forwarded_ips.include?(client_ips.last) + # We don't know which came from the proxy, and which from the user + raise IpSpoofAttackError, "IP spoofing attack?! " \ + "HTTP_CLIENT_IP=#{@req.client_ip.inspect} " \ + "HTTP_X_FORWARDED_FOR=#{@req.x_forwarded_for.inspect}" + end + + # NOTE: Mastodon addition to make sure we don't get requests from a non-trusted client + if @check_ip && (forwarded_ips.last || client_ips.last) && !@proxies.any? { |proxy| proxy === remote_addr } + raise IpSpoofAttackError, "IP spoofing attack?! client #{remote_addr} is not a trusted proxy " \ + "HTTP_CLIENT_IP=#{@req.client_ip.inspect} " \ + "HTTP_X_FORWARDED_FOR=#{@req.x_forwarded_for.inspect}" + end + + # We assume these things about the IP headers: + # + # - X-Forwarded-For will be a list of IPs, one per proxy, or blank + # - Client-Ip is propagated from the outermost proxy, or is blank + # - REMOTE_ADDR will be the IP that made the request to Rack + ips = forwarded_ips + client_ips + ips.compact! + + # If every single IP option is in the trusted list, return the IP that's + # furthest away + filter_proxies([remote_addr] + ips).first || ips.last || remote_addr + end + end + end +end + +ActionDispatch::RemoteIp::GetIp.prepend(ActionDispatch::RemoteIp::GetIpExtensions) + +# rubocop:enable all From 73a78cc19d0bff68425678c6b4c0ee0fc0a0f528 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 30 May 2024 14:56:18 +0200 Subject: [PATCH 270/658] Fix rate-limiting incorrectly triggering a session cookie on most endpoints (#30483) --- config/initializers/rack_attack.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index b3739429e8..14fab7ecda 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -30,7 +30,7 @@ class Rack::Attack end def authenticated_user_id - authenticated_token&.resource_owner_id || warden_user_id + authenticated_token&.resource_owner_id end def authenticated_token_id @@ -142,7 +142,7 @@ class Rack::Attack end throttle('throttle_password_change/account', limit: 10, period: 10.minutes) do |req| - req.authenticated_user_id if req.put? || (req.patch? && req.path_matches?('/auth')) + req.warden_user_id if req.put? || (req.patch? && req.path_matches?('/auth')) end self.throttled_responder = lambda do |request| From 7f808ff6e9148f1cfe1e16d000e2405b6e31f243 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 30 May 2024 15:34:46 +0200 Subject: [PATCH 271/658] Bump version to v4.3.0-alpha.4 (#30482) --- CHANGELOG.md | 55 +++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 6 ++--- lib/mastodon/version.rb | 2 +- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a53790afaf..c9b24d6f15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,61 @@ All notable changes to this project will be documented in this file. +## [4.2.9] - 2024-05-30 + +### Security + +- Update dependencies +- Fix private mention filtering ([GHSA-5fq7-3p3j-9vrf](https://github.com/mastodon/mastodon/security/advisories/GHSA-5fq7-3p3j-9vrf)) +- Fix password change endpoint not being rate-limited ([GHSA-q3rg-xx5v-4mxh](https://github.com/mastodon/mastodon/security/advisories/GHSA-q3rg-xx5v-4mxh)) +- Add hardening around rate-limit bypass ([GHSA-c2r5-cfqr-c553](https://github.com/mastodon/mastodon/security/advisories/GHSA-c2r5-cfqr-c553)) + +### Added + +- Add rate-limit on OAuth application registration ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/30316)) +- Add fallback redirection when getting a webfinger query `WEB_DOMAIN@WEB_DOMAIN` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28592)) +- Add `digest` attribute to `Admin::DomainBlock` entity in REST API ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/29092)) + +### Removed + +- Remove superfluous application-level caching in some controllers ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29862)) +- Remove aggressive OAuth application vacuuming ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/30316)) + +### Fixed + +- Fix leaking Elasticsearch connections in Sidekiq processes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30450)) +- Fix language of remote posts not being recognized when using unusual casing ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30403)) +- Fix off-by-one in `tootctl media` commands ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30306)) +- Fix removal of allowed domains (in `LIMITED_FEDERATION_MODE`) not being recorded in the audit log ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/30125)) +- Fix not being able to block a subdomain of an already-blocked domain through the API ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30119)) +- Fix `Idempotency-Key` being ignored when scheduling a post ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30084)) +- Fix crash when supplying the `FFMPEG_BINARY` environment variable ([timothyjrogers](https://github.com/mastodon/mastodon/pull/30022)) +- Fix improper email address validation ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29838)) +- Fix results/query in `api/v1/featured_tags/suggestions` ([mjankowski](https://github.com/mastodon/mastodon/pull/29597)) +- Fix unblocking internationalized domain names under certain conditions ([tribela](https://github.com/mastodon/mastodon/pull/29530)) +- Fix admin account created by `mastodon:setup` not being auto-approved ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29379)) +- Fix reference to non-existent var in CLI maintenance command ([mjankowski](https://github.com/mastodon/mastodon/pull/28363)) + +## [4.2.8] - 2024-02-23 + +### Added + +- Add hourly task to automatically require approval for new registrations in the absence of moderators ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29318), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/29355)) + In order to prevent future abandoned Mastodon servers from being used for spam, harassment and other malicious activity, Mastodon will now automatically switch new user registrations to require moderator approval whenever they are left open and no activity (including non-moderation actions from apps) from any logged-in user with permission to access moderation reports has been detected in a full week. + When this happens, users with the permission to change server settings will receive an email notification. + This feature is disabled when `EMAIL_DOMAIN_ALLOWLIST` is used, and can also be disabled with `DISABLE_AUTOMATIC_SWITCHING_TO_APPROVED_REGISTRATIONS=true`. + +### Changed + +- Change registrations to be closed by default on new installations ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29280)) + If you are running a server and never changed your registrations mode from the default, updating will automatically close your registrations. + Simply re-enable them through the administration interface or using `tootctl settings registrations open` if you want to enable them again. + +### Fixed + +- Fix processing of remote ActivityPub actors making use of `Link` objects as `Image` `url` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29335)) +- Fix link verifications when page size exceeds 1MB ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29358)) + ## [4.2.7] - 2024-02-16 ### Fixed diff --git a/docker-compose.yml b/docker-compose.yml index 3f2336f1d9..e7ae95ea7a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -55,7 +55,7 @@ services: web: build: . - image: ghcr.io/mastodon/mastodon:v4.2.7 + image: ghcr.io/mastodon/mastodon:v4.2.9 restart: always env_file: .env.production command: bundle exec puma -C config/puma.rb @@ -76,7 +76,7 @@ services: streaming: build: . - image: ghcr.io/mastodon/mastodon:v4.2.7 + image: ghcr.io/mastodon/mastodon:v4.2.9 restart: always env_file: .env.production command: node ./streaming @@ -94,7 +94,7 @@ services: sidekiq: build: . - image: ghcr.io/mastodon/mastodon:v4.2.7 + image: ghcr.io/mastodon/mastodon:v4.2.9 restart: always env_file: .env.production command: bundle exec sidekiq diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 1135ba0a17..03972ba938 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -17,7 +17,7 @@ module Mastodon end def default_prerelease - 'alpha.3' + 'alpha.4' end def prerelease From ad3e200bf7aa34ac7618d37532ced6a939a3e3bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 16:41:29 +0200 Subject: [PATCH 272/658] fix(deps): update dependency sass to v1.77.3 (#30476) 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 da5bf1dca2..a3490f0760 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15309,15 +15309,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.77.2 - resolution: "sass@npm:1.77.2" + version: 1.77.3 + resolution: "sass@npm:1.77.3" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/0d292339064de3c902e209d41de9c4eb2038cff326476aeebbb5be3eee1d23400d975face2b8e124ae617b10af3e93bec01580f61912f34e4c517fe137a118b6 + checksum: 10c0/131469168a4c41f9c3eeaac8a91b3ada0ff4746c8588ce1bc4b819c9245281075a895d5fc74f6edeeb32142a572af8a0799bd0ae698614a1fcfcfbd97b0b1256 languageName: node linkType: hard From a1430b710507d676716a62d042babdb3f6159c4a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 14:42:13 +0000 Subject: [PATCH 273/658] chore(deps): update dependency concurrent-ruby to v1.3.1 (#30473) 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 5c480c525c..db3e878544 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -168,7 +168,7 @@ GEM climate_control (1.2.0) cocoon (1.2.15) color_diff (0.1) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.1) connection_pool (2.4.1) cose (1.3.0) cbor (~> 0.5.9) From 00f4d9ddea4cb417a26ab547813b586a24c91e55 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 16:43:35 +0200 Subject: [PATCH 274/658] chore(deps): update dependency node to 20.14 (#30459) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 973f49d55c..c61a3d77e7 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.13 +20.14 From a0b525e50b0e53a0def7d5f4abea68737ff327f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 16:54:51 +0200 Subject: [PATCH 275/658] New Crowdin Translations (automated) (#30477) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/da.json | 3 +++ app/javascript/mastodon/locales/de.json | 1 + app/javascript/mastodon/locales/es-MX.json | 1 + app/javascript/mastodon/locales/es.json | 1 + app/javascript/mastodon/locales/fo.json | 1 + app/javascript/mastodon/locales/fy.json | 7 +++++++ app/javascript/mastodon/locales/he.json | 1 + app/javascript/mastodon/locales/hu.json | 1 + app/javascript/mastodon/locales/ia.json | 9 +++++---- app/javascript/mastodon/locales/is.json | 1 + app/javascript/mastodon/locales/nl.json | 1 + app/javascript/mastodon/locales/sr-Latn.json | 1 + app/javascript/mastodon/locales/sr.json | 1 + app/javascript/mastodon/locales/sv.json | 1 + app/javascript/mastodon/locales/tr.json | 1 + config/locales/da.yml | 1 + 16 files changed, 28 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index a23d537331..ae2968087b 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -221,6 +221,8 @@ "domain_pill.activitypub_like_language": "ActivityPub er \"sproget\", Mastodon taler med andre sociale netværk.", "domain_pill.server": "Server", "domain_pill.their_handle": "Vedkommendes handle:", + "domain_pill.their_server": "Det digitale hjem, hvor alle indlæggene findes.", + "domain_pill.their_username": "Entydig identifikator på denne server. Det er muligt at finde brugere med samme brugernavn på forskellige servere.", "domain_pill.username": "Brugernavn", "domain_pill.whats_in_a_handle": "Hvad er der i et handle (@brugernavn)?", "domain_pill.who_they_are": "Da et handle fortæller, hvem nogen er, og hvor de er, kan man interagere med folk på tværs af det sociale net af .", @@ -412,6 +414,7 @@ "limited_account_hint.action": "Vis profil alligevel", "limited_account_hint.title": "Denne profil er blevet skjult af {domain}-moderatorerne.", "link_preview.author": "Af {name}", + "link_preview.more_from_author": "Mere fra {name}", "lists.account.add": "Føj til liste", "lists.account.remove": "Fjern fra liste", "lists.delete": "Slet liste", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 5776641079..ef08e9b6d3 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Profil trotzdem anzeigen", "limited_account_hint.title": "Dieses Profil wurde von den Moderator*innen von {domain} ausgeblendet.", "link_preview.author": "Von {name}", + "link_preview.more_from_author": "Mehr von {name}", "lists.account.add": "Zur Liste hinzufügen", "lists.account.remove": "Von der Liste entfernen", "lists.delete": "Liste löschen", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 1a99d1d4b4..564d7ec57f 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Mostrar perfil de todos modos", "limited_account_hint.title": "Este perfil ha sido ocultado por los moderadores de {domain}.", "link_preview.author": "Por {name}", + "link_preview.more_from_author": "Más de {name}", "lists.account.add": "Añadir a lista", "lists.account.remove": "Quitar de lista", "lists.delete": "Borrar lista", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 1782a3a1fe..14d3bf0dda 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Mostrar perfil de todos modos", "limited_account_hint.title": "Este perfil ha sido ocultado por los moderadores de {domain}.", "link_preview.author": "Por {name}", + "link_preview.more_from_author": "Más de {name}", "lists.account.add": "Añadir a lista", "lists.account.remove": "Quitar de lista", "lists.delete": "Borrar lista", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index f22a829c0c..b77f609a2f 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Vís vangamynd kortini", "limited_account_hint.title": "Hesin vangin er fjaldur av kjakleiðarunum á {domain}.", "link_preview.author": "Av {name}", + "link_preview.more_from_author": "Meira frá {name}", "lists.account.add": "Legg afturat lista", "lists.account.remove": "Tak av lista", "lists.delete": "Strika lista", diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json index a22f4767a6..8048045c5c 100644 --- a/app/javascript/mastodon/locales/fy.json +++ b/app/javascript/mastodon/locales/fy.json @@ -89,9 +89,12 @@ "announcement.announcement": "Oankundiging", "attachments_list.unprocessed": "(net ferwurke)", "audio.hide": "Audio ferstopje", + "block_modal.remote_users_caveat": "Wy freegje de server {domain} om jo beslút te respektearjen. It neilibben hjirfan is echter net garandearre, omdat guon servers blokkaden oars ynterpretearje kinne. Iepenbiere berjochten binne mooglik noch hieltyd sichtber foar net-oanmelde brûkers.", "block_modal.show_less": "Minder toane", "block_modal.show_more": "Mear toane", "block_modal.they_cant_mention": "Sy kinne jo net fermelde of folgje.", + "block_modal.they_cant_see_posts": "De persoan kin jo berjochten net sjen en jo ek net harren berjochten.", + "block_modal.they_will_know": "De persoan kin sjen dat dy blokkearre wurdt.", "block_modal.title": "Brûker blokkearje?", "block_modal.you_wont_see_mentions": "Jo sjogge gjin berjochten mear dy’t dizze account fermelde.", "boost_modal.combo": "Jo kinne op {combo} drukke om dit de folgjende kear oer te slaan", @@ -214,11 +217,15 @@ "domain_block_modal.title": "Domein blokkearje?", "domain_block_modal.you_will_lose_followers": "Al jo folgers fan dizze server wurde ûntfolge.", "domain_block_modal.you_wont_see_posts": "Jo sjogge gjin berjochten of meldingen mear fan brûkers op dizze server.", + "domain_pill.activitypub_lets_connect": "It soarget derfoar dat jo net allinnich mar ferbine en kommunisearje kinne mei minsken op Mastodon, mar ek mei oare sosjale apps.", + "domain_pill.activitypub_like_language": "ActivityPub is de taal dy’t Mastodon mei oare sosjale netwurken sprekt.", "domain_pill.server": "Server", "domain_pill.their_handle": "Harren fediverse-adres:", "domain_pill.their_server": "Harren digitale thús, wer’t al harren berjochten binne.", + "domain_pill.their_username": "Harren unike identifikaasje-adres op harren server. It is mooglik dat der brûkers mei deselde brûkersnamme op ferskate servers te finen binne.", "domain_pill.username": "Brûkersnamme", "domain_pill.whats_in_a_handle": "Wat is in fediverse-adres?", + "domain_pill.who_they_are": "Omdat jo oan in fediverse-adres sjen kinne hoe’t ien hjit en op hokker server dy sit, kinne jo mei minsken op it troch sosjale web (fediverse) kommunisearje.", "domain_pill.your_handle": "Jo fediverse-adres:", "embed.instructions": "Embed this status on your website by copying the code below.", "embed.preview": "Sa komt it der út te sjen:", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 600de39597..dddc318473 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "הצג חשבון בכל זאת", "limited_account_hint.title": "פרופיל המשתמש הזה הוסתר על ידי המנחים של {domain}.", "link_preview.author": "מאת {name}", + "link_preview.more_from_author": "עוד מאת {name}", "lists.account.add": "הוסף לרשימה", "lists.account.remove": "הסר מרשימה", "lists.delete": "מחיקת רשימה", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index ba7fd6ddc2..dfb4b539d8 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Profil megjelenítése mindenképpen", "limited_account_hint.title": "Ezt a profilt {domain} moderátorai elrejtették.", "link_preview.author": "{name} szerint", + "link_preview.more_from_author": "Több tőle: {name}", "lists.account.add": "Hozzáadás a listához", "lists.account.remove": "Eltávolítás a listából", "lists.delete": "Lista törlése", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 47c64e3f0d..4ca2d77b3b 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -215,8 +215,8 @@ "domain_block_modal.they_cant_follow": "Necuno de iste servitor pote sequer te.", "domain_block_modal.they_wont_know": "Ille non sapera que ille ha essite blocate.", "domain_block_modal.title": "Blocar dominio?", - "domain_block_modal.you_will_lose_followers": "Omne sequitores ab iste servitor essera removite.", - "domain_block_modal.you_wont_see_posts": "Tu non videra messages e notificationes ab usatores sur iste servitor.", + "domain_block_modal.you_will_lose_followers": "Tote tu sequitores de iste servitor essera removite.", + "domain_block_modal.you_wont_see_posts": "Tu non videra messages e notificationes de usatores sur iste servitor.", "domain_pill.activitypub_lets_connect": "Illo te permitte connecter e interager con personas non solmente sur Mastodon, ma tamben sur altere applicationes social.", "domain_pill.activitypub_like_language": "ActivityPub es como le linguage commun que Mastodon parla con altere retes social.", "domain_pill.server": "Servitor", @@ -389,7 +389,7 @@ "keyboard_shortcuts.hotkey": "Clave accelerator", "keyboard_shortcuts.legend": "Monstrar iste legenda", "keyboard_shortcuts.local": "Aperir le chronologia local", - "keyboard_shortcuts.mention": "Mentionar le author", + "keyboard_shortcuts.mention": "Mentionar le autor", "keyboard_shortcuts.muted": "Aperir lista de usatores silentiate", "keyboard_shortcuts.my_profile": "Aperir tu profilo", "keyboard_shortcuts.notifications": "Aperir columna de notificationes", @@ -414,6 +414,7 @@ "limited_account_hint.action": "Monstrar profilo in omne caso", "limited_account_hint.title": "Iste profilo ha essite celate per le moderatores de {domain}.", "link_preview.author": "Per {name}", + "link_preview.more_from_author": "Plus de {name}", "lists.account.add": "Adder al lista", "lists.account.remove": "Remover del lista", "lists.delete": "Deler lista", @@ -474,7 +475,7 @@ "notification.follow_request": "{name} ha requestate de sequer te", "notification.mention": "{name} te ha mentionate", "notification.moderation-warning.learn_more": "Apprender plus", - "notification.moderation_warning": "Tu ha recepite un aviso de moderation", + "notification.moderation_warning": "Tu ha recipite un advertimento de moderation", "notification.moderation_warning.action_delete_statuses": "Alcunes de tu messages ha essite removite.", "notification.moderation_warning.action_disable": "Tu conto ha essite disactivate.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "Alcunes de tu messages ha essite marcate como sensibile.", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index f5bf7c3281..6ce72b43fc 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Birta notandasniðið samt", "limited_account_hint.title": "Þetta notandasnið hefur verið falið af umsjónarmönnum {domain}.", "link_preview.author": "Eftir {name}", + "link_preview.more_from_author": "Meira frá {name}", "lists.account.add": "Bæta á lista", "lists.account.remove": "Fjarlægja af lista", "lists.delete": "Eyða lista", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 1958e4a6a0..bf081ad588 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Alsnog het profiel tonen", "limited_account_hint.title": "Dit profiel is door de moderatoren van {domain} verborgen.", "link_preview.author": "Door {name}", + "link_preview.more_from_author": "Meer van {name}", "lists.account.add": "Aan lijst toevoegen", "lists.account.remove": "Uit lijst verwijderen", "lists.delete": "Lijst verwijderen", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 67b706fa13..a78b9ff5b4 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Ipak prikaži profil", "limited_account_hint.title": "Ovaj profil su sakrili moderatori {domain}.", "link_preview.author": "Po {name}", + "link_preview.more_from_author": "Više od {name}", "lists.account.add": "Dodaj na listu", "lists.account.remove": "Ukloni sa liste", "lists.delete": "Izbriši listu", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 9898a10a3e..5c14faea85 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Ипак прикажи профил", "limited_account_hint.title": "Овај профил су сакрили модератори {domain}.", "link_preview.author": "По {name}", + "link_preview.more_from_author": "Више од {name}", "lists.account.add": "Додај на листу", "lists.account.remove": "Уклони са листе", "lists.delete": "Избриши листу", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index ba3a6b2f51..a1d478b7ad 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Visa profil ändå", "limited_account_hint.title": "Denna profil har dolts av {domain}s moderatorer.", "link_preview.author": "Av {name}", + "link_preview.more_from_author": "Mer från {name}", "lists.account.add": "Lägg till i lista", "lists.account.remove": "Ta bort från lista", "lists.delete": "Radera lista", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 6c01106593..c0f8d083ad 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Yine de profili göster", "limited_account_hint.title": "Bu profil {domain} moderatörleri tarafından gizlendi.", "link_preview.author": "Yazar: {name}", + "link_preview.more_from_author": "{name} kişisinden daha fazlası", "lists.account.add": "Listeye ekle", "lists.account.remove": "Listeden kaldır", "lists.delete": "Listeyi sil", diff --git a/config/locales/da.yml b/config/locales/da.yml index f37086264f..cd9260dec4 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -1673,6 +1673,7 @@ da: domain_block: Serversuspendering (%{target_name}) user_domain_block: "%{target_name} blev blokeret" lost_followers: Tabte følgere + lost_follows: Mistet følger preamble: Der kan mistes fulgte objekter og følgere, når et domæne blokeres eller moderatorerne beslutter at suspendere en ekstern server. Når det sker, kan der downloades lister over afbrudte relationer til inspektion og mulig import på anden server. purged: Oplysninger om denne server er blevet renset af serveradministratoreren. type: Begivenhed From 85d9053b36674ebf1b4fdefa0028d5784b1845c7 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 30 May 2024 10:56:48 -0400 Subject: [PATCH 276/658] Move `pagination_params` into `API::BaseController` (#28845) --- .../api/v1/accounts/follower_accounts_controller.rb | 4 ---- .../api/v1/accounts/following_accounts_controller.rb | 4 ---- .../api/v1/admin/canonical_email_blocks_controller.rb | 6 ------ app/controllers/api/v1/admin/domain_allows_controller.rb | 6 ------ app/controllers/api/v1/admin/domain_blocks_controller.rb | 6 ------ .../api/v1/admin/email_domain_blocks_controller.rb | 8 -------- app/controllers/api/v1/admin/ip_blocks_controller.rb | 8 -------- app/controllers/api/v1/admin/tags_controller.rb | 5 ----- .../trends/links/preview_card_providers_controller.rb | 6 ------ app/controllers/api/v1/blocks_controller.rb | 4 ---- app/controllers/api/v1/bookmarks_controller.rb | 4 ---- app/controllers/api/v1/conversations_controller.rb | 4 ---- .../api/v1/crypto/encrypted_messages_controller.rb | 4 ---- app/controllers/api/v1/domain_blocks_controller.rb | 4 ---- app/controllers/api/v1/endorsements_controller.rb | 4 ---- app/controllers/api/v1/favourites_controller.rb | 4 ---- app/controllers/api/v1/follow_requests_controller.rb | 4 ---- app/controllers/api/v1/followed_tags_controller.rb | 4 ---- app/controllers/api/v1/lists/accounts_controller.rb | 4 ---- app/controllers/api/v1/mutes_controller.rb | 4 ---- app/controllers/api/v1/scheduled_statuses_controller.rb | 4 ---- .../api/v1/statuses/favourited_by_accounts_controller.rb | 4 ---- .../api/v1/statuses/reblogged_by_accounts_controller.rb | 4 ---- app/controllers/api/v1/statuses_controller.rb | 4 ---- app/controllers/api/v1/trends/links_controller.rb | 4 ---- app/controllers/api/v1/trends/statuses_controller.rb | 4 ---- app/controllers/api/v1/trends/tags_controller.rb | 4 ---- app/controllers/concerns/api/pagination.rb | 9 +++++++++ 28 files changed, 9 insertions(+), 125 deletions(-) diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb index 449866fa55..3f2ecb892d 100644 --- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -60,8 +60,4 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController def records_continue? @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb index c4f4313f8f..7c16a3487e 100644 --- a/app/controllers/api/v1/accounts/following_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -60,8 +60,4 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController def records_continue? @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/admin/canonical_email_blocks_controller.rb b/app/controllers/api/v1/admin/canonical_email_blocks_controller.rb index 701f668de6..c144a9e0f9 100644 --- a/app/controllers/api/v1/admin/canonical_email_blocks_controller.rb +++ b/app/controllers/api/v1/admin/canonical_email_blocks_controller.rb @@ -16,8 +16,6 @@ class Api::V1::Admin::CanonicalEmailBlocksController < Api::BaseController after_action :verify_authorized after_action :insert_pagination_headers, only: :index - PAGINATION_PARAMS = %i(limit).freeze - def index authorize :canonical_email_block, :index? render json: @canonical_email_blocks, each_serializer: REST::Admin::CanonicalEmailBlockSerializer @@ -80,8 +78,4 @@ class Api::V1::Admin::CanonicalEmailBlocksController < Api::BaseController def records_continue? @canonical_email_blocks.size == limit_param(LIMIT) end - - def pagination_params(core_params) - params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) - end end diff --git a/app/controllers/api/v1/admin/domain_allows_controller.rb b/app/controllers/api/v1/admin/domain_allows_controller.rb index a7ae84e306..9801d832b8 100644 --- a/app/controllers/api/v1/admin/domain_allows_controller.rb +++ b/app/controllers/api/v1/admin/domain_allows_controller.rb @@ -14,8 +14,6 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController after_action :verify_authorized after_action :insert_pagination_headers, only: :index - PAGINATION_PARAMS = %i(limit).freeze - def index authorize :domain_allow, :index? render json: @domain_allows, each_serializer: REST::Admin::DomainAllowSerializer @@ -77,10 +75,6 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController @domain_allows.size == limit_param(LIMIT) end - def pagination_params(core_params) - params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) - end - def resource_params params.permit(:domain) end diff --git a/app/controllers/api/v1/admin/domain_blocks_controller.rb b/app/controllers/api/v1/admin/domain_blocks_controller.rb index ae94ac59cd..a20a4a9c7f 100644 --- a/app/controllers/api/v1/admin/domain_blocks_controller.rb +++ b/app/controllers/api/v1/admin/domain_blocks_controller.rb @@ -14,8 +14,6 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController after_action :verify_authorized after_action :insert_pagination_headers, only: :index - PAGINATION_PARAMS = %i(limit).freeze - def index authorize :domain_block, :index? render json: @domain_blocks, each_serializer: REST::Admin::DomainBlockSerializer @@ -93,10 +91,6 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController @domain_blocks.size == limit_param(LIMIT) end - def pagination_params(core_params) - params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) - end - def resource_params params.permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate) end diff --git a/app/controllers/api/v1/admin/email_domain_blocks_controller.rb b/app/controllers/api/v1/admin/email_domain_blocks_controller.rb index bdedb9d040..e7bd804e36 100644 --- a/app/controllers/api/v1/admin/email_domain_blocks_controller.rb +++ b/app/controllers/api/v1/admin/email_domain_blocks_controller.rb @@ -14,10 +14,6 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController after_action :verify_authorized after_action :insert_pagination_headers, only: :index - PAGINATION_PARAMS = %i( - limit - ).freeze - def index authorize :email_domain_block, :index? render json: @email_domain_blocks, each_serializer: REST::Admin::EmailDomainBlockSerializer @@ -73,8 +69,4 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController def records_continue? @email_domain_blocks.size == limit_param(LIMIT) end - - def pagination_params(core_params) - params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) - end end diff --git a/app/controllers/api/v1/admin/ip_blocks_controller.rb b/app/controllers/api/v1/admin/ip_blocks_controller.rb index 3625781149..e132a3a87d 100644 --- a/app/controllers/api/v1/admin/ip_blocks_controller.rb +++ b/app/controllers/api/v1/admin/ip_blocks_controller.rb @@ -14,10 +14,6 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController after_action :verify_authorized after_action :insert_pagination_headers, only: :index - PAGINATION_PARAMS = %i( - limit - ).freeze - def index authorize :ip_block, :index? render json: @ip_blocks, each_serializer: REST::Admin::IpBlockSerializer @@ -78,8 +74,4 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController def records_continue? @ip_blocks.size == limit_param(LIMIT) end - - def pagination_params(core_params) - params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) - end end diff --git a/app/controllers/api/v1/admin/tags_controller.rb b/app/controllers/api/v1/admin/tags_controller.rb index c754980720..67d987d0e3 100644 --- a/app/controllers/api/v1/admin/tags_controller.rb +++ b/app/controllers/api/v1/admin/tags_controller.rb @@ -12,7 +12,6 @@ class Api::V1::Admin::TagsController < Api::BaseController after_action :verify_authorized LIMIT = 100 - PAGINATION_PARAMS = %i(limit).freeze def index authorize :tag, :index? @@ -59,8 +58,4 @@ class Api::V1::Admin::TagsController < Api::BaseController def records_continue? @tags.size == limit_param(LIMIT) end - - def pagination_params(core_params) - params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) - end end diff --git a/app/controllers/api/v1/admin/trends/links/preview_card_providers_controller.rb b/app/controllers/api/v1/admin/trends/links/preview_card_providers_controller.rb index 8bb5e22716..2b0f39b98f 100644 --- a/app/controllers/api/v1/admin/trends/links/preview_card_providers_controller.rb +++ b/app/controllers/api/v1/admin/trends/links/preview_card_providers_controller.rb @@ -12,8 +12,6 @@ class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseC after_action :verify_authorized after_action :insert_pagination_headers, only: :index - PAGINATION_PARAMS = %i(limit).freeze - def index authorize :preview_card_provider, :index? @@ -57,8 +55,4 @@ class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseC def records_continue? @providers.size == limit_param(LIMIT) end - - def pagination_params(core_params) - params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) - end end diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb index 234ab2e82c..d7516c927b 100644 --- a/app/controllers/api/v1/blocks_controller.rb +++ b/app/controllers/api/v1/blocks_controller.rb @@ -43,8 +43,4 @@ class Api::V1::BlocksController < Api::BaseController def records_continue? paginated_blocks.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/bookmarks_controller.rb b/app/controllers/api/v1/bookmarks_controller.rb index f7671a9032..29f08e81d2 100644 --- a/app/controllers/api/v1/bookmarks_controller.rb +++ b/app/controllers/api/v1/bookmarks_controller.rb @@ -46,8 +46,4 @@ class Api::V1::BookmarksController < Api::BaseController def records_continue? results.size == limit_param(DEFAULT_STATUSES_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/conversations_controller.rb b/app/controllers/api/v1/conversations_controller.rb index a29b908555..60db082a8e 100644 --- a/app/controllers/api/v1/conversations_controller.rb +++ b/app/controllers/api/v1/conversations_controller.rb @@ -72,8 +72,4 @@ class Api::V1::ConversationsController < Api::BaseController def records_continue? @conversations.size == limit_param(LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/crypto/encrypted_messages_controller.rb b/app/controllers/api/v1/crypto/encrypted_messages_controller.rb index d3de220393..93ae0e7771 100644 --- a/app/controllers/api/v1/crypto/encrypted_messages_controller.rb +++ b/app/controllers/api/v1/crypto/encrypted_messages_controller.rb @@ -44,8 +44,4 @@ class Api::V1::Crypto::EncryptedMessagesController < Api::BaseController def records_continue? @encrypted_messages.size == limit_param(LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/domain_blocks_controller.rb b/app/controllers/api/v1/domain_blocks_controller.rb index 3dee2d176c..780ecbf189 100644 --- a/app/controllers/api/v1/domain_blocks_controller.rb +++ b/app/controllers/api/v1/domain_blocks_controller.rb @@ -54,10 +54,6 @@ class Api::V1::DomainBlocksController < Api::BaseController @blocks.size == limit_param(BLOCK_LIMIT) end - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - def domain_block_params params.permit(:domain) end diff --git a/app/controllers/api/v1/endorsements_controller.rb b/app/controllers/api/v1/endorsements_controller.rb index 9a723d89e4..09bafe0231 100644 --- a/app/controllers/api/v1/endorsements_controller.rb +++ b/app/controllers/api/v1/endorsements_controller.rb @@ -48,10 +48,6 @@ class Api::V1::EndorsementsController < Api::BaseController @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - def unlimited? params[:limit] == '0' end diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb index 18ca9ab866..a4454e4ded 100644 --- a/app/controllers/api/v1/favourites_controller.rb +++ b/app/controllers/api/v1/favourites_controller.rb @@ -46,8 +46,4 @@ class Api::V1::FavouritesController < Api::BaseController def records_continue? results.size == limit_param(DEFAULT_STATUSES_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb index 7ffd7614bb..29a09fceef 100644 --- a/app/controllers/api/v1/follow_requests_controller.rb +++ b/app/controllers/api/v1/follow_requests_controller.rb @@ -67,8 +67,4 @@ class Api::V1::FollowRequestsController < Api::BaseController def records_continue? @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/followed_tags_controller.rb b/app/controllers/api/v1/followed_tags_controller.rb index 8888612b16..7d8f0eda1e 100644 --- a/app/controllers/api/v1/followed_tags_controller.rb +++ b/app/controllers/api/v1/followed_tags_controller.rb @@ -37,8 +37,4 @@ class Api::V1::FollowedTagsController < Api::BaseController def records_continue? @results.size == limit_param(TAGS_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/lists/accounts_controller.rb b/app/controllers/api/v1/lists/accounts_controller.rb index aecf391049..b1c0e609d0 100644 --- a/app/controllers/api/v1/lists/accounts_controller.rb +++ b/app/controllers/api/v1/lists/accounts_controller.rb @@ -75,10 +75,6 @@ class Api::V1::Lists::AccountsController < Api::BaseController @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - def unlimited? params[:limit] == '0' end diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb index dbfd7e103a..d2b50e3336 100644 --- a/app/controllers/api/v1/mutes_controller.rb +++ b/app/controllers/api/v1/mutes_controller.rb @@ -43,8 +43,4 @@ class Api::V1::MutesController < Api::BaseController def records_continue? paginated_mutes.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/scheduled_statuses_controller.rb b/app/controllers/api/v1/scheduled_statuses_controller.rb index 1217ed014e..45ee586518 100644 --- a/app/controllers/api/v1/scheduled_statuses_controller.rb +++ b/app/controllers/api/v1/scheduled_statuses_controller.rb @@ -43,10 +43,6 @@ class Api::V1::ScheduledStatusesController < Api::BaseController params.permit(:scheduled_at) end - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - def next_path api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id) if records_continue? end diff --git a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb index bbc8082e0c..5a5c2fdc97 100644 --- a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb @@ -53,8 +53,4 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::V1::Statuses::Bas def records_continue? @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb index bac96b032b..0eba4fae32 100644 --- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb @@ -49,8 +49,4 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::V1::Statuses::Base def records_continue? @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index cca3865f62..19cc71ae58 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -188,8 +188,4 @@ class Api::V1::StatusesController < Api::BaseController def serialized_accounts(accounts) ActiveModel::Serializer::CollectionSerializer.new(accounts, serializer: REST::AccountSerializer) end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end end diff --git a/app/controllers/api/v1/trends/links_controller.rb b/app/controllers/api/v1/trends/links_controller.rb index 8edf5bbcef..3c5aecff43 100644 --- a/app/controllers/api/v1/trends/links_controller.rb +++ b/app/controllers/api/v1/trends/links_controller.rb @@ -34,10 +34,6 @@ class Api::V1::Trends::LinksController < Api::BaseController scope end - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - def next_path api_v1_trends_links_url pagination_params(offset: offset_param + limit_param(DEFAULT_LINKS_LIMIT)) if records_continue? end diff --git a/app/controllers/api/v1/trends/statuses_controller.rb b/app/controllers/api/v1/trends/statuses_controller.rb index c6fbbce167..cdbfce0685 100644 --- a/app/controllers/api/v1/trends/statuses_controller.rb +++ b/app/controllers/api/v1/trends/statuses_controller.rb @@ -32,10 +32,6 @@ class Api::V1::Trends::StatusesController < Api::BaseController scope end - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - def next_path api_v1_trends_statuses_url pagination_params(offset: offset_param + limit_param(DEFAULT_STATUSES_LIMIT)) if records_continue? end diff --git a/app/controllers/api/v1/trends/tags_controller.rb b/app/controllers/api/v1/trends/tags_controller.rb index 6d3855a90a..b15dd50131 100644 --- a/app/controllers/api/v1/trends/tags_controller.rb +++ b/app/controllers/api/v1/trends/tags_controller.rb @@ -30,10 +30,6 @@ class Api::V1::Trends::TagsController < Api::BaseController Trends.tags.query.allowed end - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - def next_path api_v1_trends_tags_url pagination_params(offset: offset_param + limit_param(DEFAULT_TAGS_LIMIT)) if records_continue? end diff --git a/app/controllers/concerns/api/pagination.rb b/app/controllers/concerns/api/pagination.rb index d84a1d99f7..7f06dc0202 100644 --- a/app/controllers/concerns/api/pagination.rb +++ b/app/controllers/concerns/api/pagination.rb @@ -3,6 +3,8 @@ module Api::Pagination extend ActiveSupport::Concern + PAGINATION_PARAMS = %i(limit).freeze + protected def pagination_max_id @@ -24,6 +26,13 @@ module Api::Pagination render json: { error: 'Pagination values for `offset` and `limit` must be positive' }, status: 400 if pagination_options_invalid? end + def pagination_params(core_params) + params + .slice(*PAGINATION_PARAMS) + .permit(*PAGINATION_PARAMS) + .merge(core_params) + end + private def insert_pagination_headers From ced700743670372677affb7b7da811d04abbdf77 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 11:08:31 +0200 Subject: [PATCH 277/658] chore(deps): update dependency rubocop to v1.64.1 (#30500) 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 db3e878544..33053948c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -579,7 +579,7 @@ GEM orm_adapter (0.5.0) ox (2.14.18) parallel (1.24.0) - parser (3.3.1.0) + parser (3.3.2.0) ast (~> 2.4.1) racc parslet (2.0.0) @@ -726,7 +726,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 8) rspec-support (3.13.1) - rubocop (1.64.0) + rubocop (1.64.1) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) From 9533a8632b5059f7e089f020c0e2fe00c798f640 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 11:26:31 +0200 Subject: [PATCH 278/658] chore(deps): update dependency ruby to v3.3.2 (#30480) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index bea438e9ad..4772543317 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.1 +3.3.2 From 543fa2691626174b1dbed3af13e2e3c0e9e2294a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 11:26:40 +0200 Subject: [PATCH 279/658] fix(deps): update dependency sass to v1.77.4 (#30496) 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 a3490f0760..f77dedd4b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15309,15 +15309,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.77.3 - resolution: "sass@npm:1.77.3" + version: 1.77.4 + resolution: "sass@npm:1.77.4" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/131469168a4c41f9c3eeaac8a91b3ada0ff4746c8588ce1bc4b819c9245281075a895d5fc74f6edeeb32142a572af8a0799bd0ae698614a1fcfcfbd97b0b1256 + checksum: 10c0/b9cb4882bded282aabe38d011adfce375e1f282184fcf93dc3da5d5be834c6aa53c474c15634c351ef7bd85146cfd1cc81343654cc3bcf000d78e856da4225ef languageName: node linkType: hard From dac4eba46b918e7be1153c7acf6b6f62ca644f59 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 11:26:52 +0200 Subject: [PATCH 280/658] New Crowdin Translations (automated) (#30499) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/bg.json | 1 + app/javascript/mastodon/locales/ia.json | 10 +-- app/javascript/mastodon/locales/lad.json | 1 + app/javascript/mastodon/locales/lt.json | 5 +- app/javascript/mastodon/locales/lv.json | 15 +++- app/javascript/mastodon/locales/sq.json | 1 + app/javascript/mastodon/locales/th.json | 1 + app/javascript/mastodon/locales/uk.json | 1 + config/locales/devise.lt.yml | 8 +- config/locales/lt.yml | 95 ++++++++++++++++++++---- config/locales/simple_form.ia.yml | 14 ++-- 11 files changed, 120 insertions(+), 32 deletions(-) diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 95d60b71eb..b17172058b 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Показване на профила въпреки това", "limited_account_hint.title": "Този профил е бил скрит от модераторите на {domain}.", "link_preview.author": "От {name}", + "link_preview.more_from_author": "Още от {name}", "lists.account.add": "Добавяне към списък", "lists.account.remove": "Премахване от списъка", "lists.delete": "Изтриване на списъка", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 4ca2d77b3b..4bcf4c88b5 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -494,7 +494,7 @@ "notification.status": "{name} ha justo ora publicate", "notification.update": "{name} ha modificate un message", "notification_requests.accept": "Acceptar", - "notification_requests.dismiss": "Dimitter", + "notification_requests.dismiss": "Clauder", "notification_requests.notifications_from": "Notificationes de {name}", "notification_requests.title": "Notificationes filtrate", "notifications.clear": "Rader notificationes", @@ -622,7 +622,7 @@ "relative_time.today": "hodie", "reply_indicator.attachments": "{count, plural, one {# annexo} other {# annexos}}", "reply_indicator.cancel": "Cancellar", - "reply_indicator.poll": "Inquesta", + "reply_indicator.poll": "Sondage", "report.block": "Blocar", "report.block_explanation": "Tu non videra le messages de iste persona. Ille non potera vider tu messages o sequer te. Ille potera saper de esser blocate.", "report.categories.legal": "Juridic", @@ -678,7 +678,7 @@ "search.quick_action.status_search": "Messages correspondente a {x}", "search.search_or_paste": "Cerca o colla un URL", "search_popout.full_text_search_disabled_message": "Non disponibile sur {domain}.", - "search_popout.full_text_search_logged_out_message": "Solmente disponibile al initiar le session.", + "search_popout.full_text_search_logged_out_message": "Solmente disponibile post aperir session.", "search_popout.language_code": "Codice de lingua ISO", "search_popout.options": "Optiones de recerca", "search_popout.quick_actions": "Actiones rapide", @@ -758,7 +758,7 @@ "status.show_original": "Monstrar original", "status.title.with_attachments": "{user} ha publicate {attachmentCount, plural, one {un annexo} other {{attachmentCount} annexos}}", "status.translate": "Traducer", - "status.translated_from_with": "Traducite ab {lang} usante {provider}", + "status.translated_from_with": "Traducite de {lang} usante {provider}", "status.uncached_media_warning": "Previsualisation non disponibile", "status.unmute_conversation": "Non plus silentiar conversation", "status.unpin": "Disfixar del profilo", @@ -797,7 +797,7 @@ "upload_modal.choose_image": "Seliger un imagine", "upload_modal.description_placeholder": "Cinque expertos del zoo jam bibeva whisky frigide", "upload_modal.detect_text": "Deteger texto de un imagine", - "upload_modal.edit_media": "Modificar le medio", + "upload_modal.edit_media": "Modificar multimedia", "upload_modal.hint": "Clicca o trahe le circulo sur le previsualisation pro eliger le puncto focal que essera sempre visibile sur tote le miniaturas.", "upload_modal.preparing_ocr": "Preparation del OCR…", "upload_modal.preview_label": "Previsualisation ({ratio})", diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json index 533f074004..72299bb861 100644 --- a/app/javascript/mastodon/locales/lad.json +++ b/app/javascript/mastodon/locales/lad.json @@ -398,6 +398,7 @@ "limited_account_hint.action": "Amostra el profil entanto", "limited_account_hint.title": "Este profil fue eskondido por los moderadores de {domain}.", "link_preview.author": "Publikasyon de {name}", + "link_preview.more_from_author": "Mas de {name}", "lists.account.add": "Adjusta a lista", "lists.account.remove": "Kita de lista", "lists.delete": "Efasa lista", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 5fc7d32869..40541b3757 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Vis tiek rodyti profilį", "limited_account_hint.title": "Šį profilį paslėpė {domain} prižiūrėtojai.", "link_preview.author": "Sukūrė {name}", + "link_preview.more_from_author": "Daugiau iš {name}", "lists.account.add": "Pridėti į sąrašą", "lists.account.remove": "Pašalinti iš sąrašo", "lists.delete": "Ištrinti sąrašą", @@ -561,7 +562,7 @@ "onboarding.steps.setup_profile.title": "Suasmenink savo profilį", "onboarding.steps.share_profile.body": "Leisk draugams sužinoti, kaip tave rasti Mastodon.", "onboarding.steps.share_profile.title": "Bendrink savo Mastodon profilį", - "onboarding.tips.2fa": "Ar žinojai? Savo paskyrą gali apsaugoti nustatęs (-usi) dviejų veiksnių tapatybės nustatymą paskyros nustatymuose. Jis veikia su bet kuria pasirinkta TOTP programėle, telefono numeris nebūtinas.", + "onboarding.tips.2fa": "Ar žinojai? Savo paskyrą gali apsaugoti nustatant dviejų veiksnių tapatybės nustatymą paskyros nustatymuose. Jis veikia su bet kuria pasirinkta TOTP programėle, telefono numeris nebūtinas.", "onboarding.tips.accounts_from_other_servers": "Ar žinojai? Kadangi Mastodon decentralizuotas, kai kurie profiliai, su kuriais susidursi, bus talpinami ne tavo, o kituose serveriuose. Ir vis tiek galėsi su jais sklandžiai bendrauti! Jų serveris yra antroje naudotojo vardo pusėje.", "onboarding.tips.migration": "Ar žinojai? Jei manai, kad {domain} serveris ateityje tau netiks, gali persikelti į kitą Mastodon serverį neprarandant savo sekėjų. Gali net talpinti savo paties serverį.", "onboarding.tips.verification": "Ar žinojai? Savo paskyrą gali patvirtinti pateikęs (-usi) nuorodą į Mastodon profilį savo interneto svetainėje ir pridėjęs (-usi) svetainę prie savo profilio. Nereikia jokių mokesčių ar dokumentų.", @@ -632,7 +633,7 @@ "report.reasons.legal_description": "Manai, kad tai pažeidžia tavo arba serverio šalies įstatymus", "report.reasons.other": "Tai kažkas kita", "report.reasons.other_description": "Problema netinka kitoms kategorijoms", - "report.reasons.spam": "Tai šlamštas", + "report.reasons.spam": "Tai – šlamštas", "report.reasons.spam_description": "Kenkėjiškos nuorodos, netikras įsitraukimas arba pasikartojantys atsakymai", "report.reasons.violation": "Tai pažeidžia serverio taisykles", "report.reasons.violation_description": "Žinai, kad tai pažeidžia konkrečias taisykles", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index b61a2c0c36..7a1d583d9a 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -92,6 +92,8 @@ "block_modal.remote_users_caveat": "Mēs vaicāsim serverim {domain} ņemt vērā Tavu lēmumu. Tomēr atbilstība nav nodrošināta, jo atsevišķi serveri var apstrādāt bloķēšanu citādi. Publiski ieraksti joprojām var būt redzami lietotājiem, kuri nav pieteikušies.", "block_modal.show_less": "Rādīt mazāk", "block_modal.show_more": "Parādīt mazāk", + "block_modal.they_cant_mention": "Nevar Tevi pieminēt vai sekot Tev.", + "block_modal.they_cant_see_posts": "Nevar redzēt Tavus ierakstus, un Tu neredzēsi lietotāja.", "boost_modal.combo": "Nospied {combo}, lai nākamreiz šo izlaistu", "bundle_column_error.copy_stacktrace": "Kopēt kļūdu ziņojumu", "bundle_column_error.error.body": "Pieprasīto lapu nevarēja atveidot. Tas varētu būt saistīts ar kļūdu mūsu kodā, vai tā ir pārlūkprogrammas saderības problēma.", @@ -377,6 +379,7 @@ "limited_account_hint.action": "Tik un tā rādīt profilu", "limited_account_hint.title": "{domain} moderatori ir paslēpuši šo profilu.", "link_preview.author": "Pēc {name}", + "link_preview.more_from_author": "Vairāk no {name}", "lists.account.add": "Pievienot sarakstam", "lists.account.remove": "Noņemt no saraksta", "lists.delete": "Izdzēst sarakstu", @@ -448,12 +451,15 @@ "notification_requests.accept": "Pieņemt", "notification_requests.dismiss": "Noraidīt", "notification_requests.notifications_from": "Paziņojumi no {name}", + "notification_requests.title": "Atlasītie paziņojumi", "notifications.clear": "Notīrīt paziņojumus", "notifications.clear_confirmation": "Vai tiešām vēlies neatgriezeniski notīrīt visus savus paziņojumus?", "notifications.column_settings.admin.report": "Jauni ziņojumi:", "notifications.column_settings.admin.sign_up": "Jaunas pierakstīšanās:", "notifications.column_settings.alert": "Darbvirsmas paziņojumi", "notifications.column_settings.favourite": "Izlase:", + "notifications.column_settings.filter_bar.advanced": "Attēlot visas kategorijas", + "notifications.column_settings.filter_bar.category": "Atrās atlasīšanas josla", "notifications.column_settings.follow": "Jauni sekotāji:", "notifications.column_settings.follow_request": "Jauni sekošanas pieprasījumi:", "notifications.column_settings.mention": "Pieminēšanas:", @@ -481,7 +487,9 @@ "notifications.permission_required": "Darbvirsmas paziņojumi nav pieejami, jo nav piešķirta nepieciešamā atļauja.", "notifications.policy.filter_new_accounts_title": "Jauni konti", "notifications.policy.filter_not_followers_title": "Cilvēki, kuri Tev neseko", + "notifications.policy.filter_not_following_hint": "Līdz tos pašrocīgi apstiprināsi", "notifications.policy.filter_not_following_title": "Cilvēki, kuriem Tu neseko", + "notifications.policy.title": "Atlasīt paziņojumus no…", "notifications_permission_banner.enable": "Iespējot darbvirsmas paziņojumus", "notifications_permission_banner.how_to_control": "Lai saņemtu paziņojumus, kad Mastodon nav atvērts, iespējo darbvirsmas paziņojumus. Vari precīzi kontrolēt, kāda veida mijiedarbības rada darbvirsmas paziņojumus, izmantojot augstāk redzamo pogu {icon}, kad tie būs iespējoti.", "notifications_permission_banner.title": "Nekad nepalaid neko garām", @@ -539,7 +547,9 @@ "privacy.direct.short": "Noteikti cilvēki", "privacy.private.long": "Tikai Tavi sekotāji", "privacy.private.short": "Sekotāji", + "privacy.public.long": "Jebkurš Mastodon un ārpus tā", "privacy.public.short": "Publiska", + "privacy.unlisted.long": "Mazāk algoritmisku fanfaru", "privacy_policy.last_updated": "Pēdējo reizi atjaunināta {date}", "privacy_policy.title": "Privātuma politika", "recommended": "Ieteicams", @@ -557,6 +567,7 @@ "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", "relative_time.today": "šodien", + "reply_indicator.attachments": "{count, plural, zero{# pielikumu} one {# pielikums} other {# pielikumi}}", "reply_indicator.cancel": "Atcelt", "reply_indicator.poll": "Aptauja", "report.block": "Bloķēt", @@ -630,7 +641,7 @@ "search_results.title": "Meklēt {q}", "server_banner.about_active_users": "Cilvēki, kas izmantojuši šo serveri pēdējo 30 dienu laikā (aktīvie lietotāji mēnesī)", "server_banner.active_users": "aktīvi lietotāji", - "server_banner.administered_by": "Administrē:", + "server_banner.administered_by": "Pārvalda:", "server_banner.introduction": "{domain} ir daļa no decentralizētā sociālā tīkla, ko nodrošina {mastodon}.", "server_banner.learn_more": "Uzzināt vairāk", "server_banner.server_stats": "Servera statistika:", @@ -655,6 +666,7 @@ "status.edited_x_times": "Labots {count, plural, one {{count} reizi} other {{count} reizes}}", "status.embed": "Iegult", "status.favourite": "Izlasē", + "status.favourites": "{count, plural, zero {izlasēs} one {izlasē} other {izlasēs}}", "status.filter": "Filtrē šo ziņu", "status.filtered": "Filtrēts", "status.hide": "Slēpt ierakstu", @@ -675,6 +687,7 @@ "status.reblog": "Pastiprināt", "status.reblog_private": "Pastiprināt, nemainot redzamību", "status.reblogged_by": "{name} pastiprināja", + "status.reblogs": "{count, plural, zero {pastiprinājumu} one {pastiprinājums} other {pastiprinājumi}}", "status.reblogs.empty": "Neviens šo ierakstu vēl nav pastiprinājis. Kad būs, tie parādīsies šeit.", "status.redraft": "Dzēst un pārrakstīt", "status.remove_bookmark": "Noņemt grāmatzīmi", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index b496f8e203..6b3c5fbd90 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Shfaqe profilin sido qoftë", "limited_account_hint.title": "Ky profil është fshehur nga moderatorët e {domain}.", "link_preview.author": "Nga {name}", + "link_preview.more_from_author": "Më tepër nga {name}", "lists.account.add": "Shto në listë", "lists.account.remove": "Hiqe nga lista", "lists.delete": "Fshije listën", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index b1b9407ba1..e16e393575 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "แสดงโปรไฟล์ต่อไป", "limited_account_hint.title": "มีการซ่อนโปรไฟล์นี้โดยผู้กลั่นกรองของ {domain}", "link_preview.author": "โดย {name}", + "link_preview.more_from_author": "เพิ่มเติมจาก {name}", "lists.account.add": "เพิ่มไปยังรายการ", "lists.account.remove": "เอาออกจากรายการ", "lists.delete": "ลบรายการ", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 3a7f63206d..f750fce040 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -414,6 +414,7 @@ "limited_account_hint.action": "Усе одно показати профіль", "limited_account_hint.title": "Цей профіль сховали модератори {domain}.", "link_preview.author": "Від {name}", + "link_preview.more_from_author": "Більше від {name}", "lists.account.add": "Додати до списку", "lists.account.remove": "Вилучити зі списку", "lists.delete": "Видалити список", diff --git a/config/locales/devise.lt.yml b/config/locales/devise.lt.yml index e36e60a758..f27b68b708 100644 --- a/config/locales/devise.lt.yml +++ b/config/locales/devise.lt.yml @@ -76,7 +76,7 @@ lt: webauthn_disabled: explanation: Tavo paskyrai išjungtas tapatybės nustatymas naudojant saugumo raktus. extra: Prisijungimas dabar galimas naudojant tik susietos TOTP programėlės sugeneruotą prieigos raktą. - subject: 'Mastodon: tapatybės nustatymas naudojant saugumo raktai išjungta' + subject: 'Mastodon: tapatybės nustatymas su saugumo raktai išjungta' title: Saugumo raktai išjungti webauthn_enabled: explanation: Tavo paskyrai įjungtas saugumo rakto tapatybės nustatymas. @@ -98,8 +98,8 @@ lt: signed_up_but_inactive: Sėkmingai užsiregistravai. Tačiau negalėjome tavęs prijungti, nes tavo paskyra dar nėra aktyvuota. signed_up_but_locked: Sėkmingai užsiregistravai. Tačiau negalėjome tavęs prijungti, nes tavo paskyra dar užrakinta. signed_up_but_pending: Į tavo el. pašto adresą buvo išsiųstas laiškas su patvirtinimo nuoroda. Paspaudęs (-usi) nuorodą, peržiūrėsime tavo paraišką. Tau bus pranešta, jei ji patvirtinta. - signed_up_but_unconfirmed: Į tavo el. pašto adresą buvo išsiųstas laiškas su patvirtinimo nuoroda. Paspausk nuorodą, kad aktyvuotum savo paskyrą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. - update_needs_confirmation: Sėkmingai atnaujinai savo paskyrą, bet mums reikia patvirtinti naująjį el. pašto adresą. Patikrink savo el. paštą ir paspausk patvirtinimo nuorodą, kad patvirtintum savo naują el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + signed_up_but_unconfirmed: Į tavo el. pašto adresą buvo išsiųstas laiškas su patvirtinimo nuoroda. Sek nuorodą, kad aktyvuotum savo paskyrą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + update_needs_confirmation: Sėkmingai atnaujinai savo paskyrą, bet mums reikia patvirtinti naująjį el. pašto adresą. Patikrink savo el. paštą ir sek patvirtinimo nuorodą, kad patvirtintum savo naują el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. updated: Tavo paskyra buvo sėkmingai atnaujinta. sessions: already_signed_out: Atsijungta sėkmingai. @@ -107,7 +107,7 @@ lt: signed_out: Atjungta sėkmingai. unlocks: send_instructions: Po kelių minučių gausi el. laišką su instrukcijomis, kaip atrakinti paskyrą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. - send_paranoid_instructions: Jei paskyra egzistuoja, po kelių minučių gausi el. laišką su instrukcijomis, kaip ją atrakinti. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + send_paranoid_instructions: Jei tavo paskyra egzistuoja, po kelių minučių gausi el. laišką su instrukcijomis, kaip ją atrakinti. Jei negavai šio el. laiško, patikrink šlamšto aplanką. unlocked: Tavo paskyra sėkmingai atrakinta. Norėdamas (-a) tęsti, prisijunk. errors: messages: diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 77fcf42866..c29218c1fe 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -265,10 +265,10 @@ lt: destroy_user_role_html: "%{name} ištrynė %{target} vaidmenį" disable_2fa_user_html: "%{name} išjungė dviejų veiksnių reikalavimą naudotojui %{target}" disable_custom_emoji_html: "%{name} išjungė jaustuką %{target}" - disable_sign_in_token_auth_user_html: "%{name} išjungė el. pašto prieigos tapatybės nustatymą %{target}" + disable_sign_in_token_auth_user_html: "%{name} išjungė el. pašto prieigos tapatybės nustatymą naudotojui %{target}" disable_user_html: "%{name} išjungė prisijungimą naudotojui %{target}" enable_custom_emoji_html: "%{name} įjungė jaustuką %{target}" - enable_sign_in_token_auth_user_html: "%{name} įjungė el. pašto prieigos tapatybės nustatymą %{target}" + enable_sign_in_token_auth_user_html: "%{name} įjungė el. pašto prieigos tapatybės nustatymą naudotojui %{target}" enable_user_html: "%{name} įjungė prisijungimą naudotojui %{target}" memorialize_account_html: "%{name} pavertė %{target} paskyrą į atminimo puslapį" promote_user_html: "%{name} paaukštino naudotoją %{target}" @@ -440,6 +440,9 @@ lt: create: Pridėto domeną title: Naujas el pašto juodojo sąrašo įtraukimas title: El pašto juodasis sąrašas + export_domain_blocks: + import: + description_html: Netrukus importuosi domenų blokavimų sąrašą. Labai atidžiai peržiūrėk šį sąrašą, ypač jei ne tu jį sudarei. instances: availability: title: Prieinamumas @@ -493,6 +496,7 @@ lt: destroyed_msg: Skundo žinutė sekmingai ištrinta! reports: action_taken_by: Veiksmo ėmėsi + actions_description_html: Nuspręsk, kokių veiksmų imtis, kad išspręstum šią ataskaitą. Jei imsis baudžiamųjų veiksmų prieš paskyrą, apie kurią pranešta, jiems bus išsiųstas el. laiško pranešimas, išskyrus atvejus, kai pasirinkta kategorija Šlamštas. already_suspended_badges: local: Jau sustabdytas šiame serveryje remote: Jau sustabdytas jų serveryje @@ -534,6 +538,7 @@ lt: manage_invites: Tvarkyti kvietimus manage_invites_description: Leidžia naudotojams naršyti ir deaktyvuoti kvietimų nuorodas. manage_taxonomies_description: Leidžia naudotojams peržiūrėti tendencingą turinį ir atnaujinti saitažodžių nustatymus + manage_user_access_description: Leidžia naudotojams išjungti kitų naudotojų dvigubo tapatybės nustatymą, pakeisti el. pašto adresą ir iš naujo nustatyti slaptažodį. settings: captcha_enabled: desc_html: Tai priklauso nuo hCaptcha išorinių skriptų, kurie gali kelti susirūpinimą dėl saugumo ir privatumo. Be to, dėl to registracijos procesas kai kuriems žmonėms (ypač neįgaliesiems) gali būti gerokai sunkiau prieinami. Dėl šių priežasčių apsvarstyk alternatyvias priemones, pavyzdžiui, patvirtinimu arba kvietimu grindžiamą registraciją. @@ -546,6 +551,15 @@ lt: all: Visiems registrations: moderation_recommandation: Prieš atidarant registraciją visiems, įsitikink, kad turi tinkamą ir reaguojančią prižiūrėjimo komandą! + registrations_mode: + modes: + approved: Registracijai privalomas patvirtinimas + warning_hint: Rekomenduojame naudoti „Registracijai privalomas patvirtinimas“, nebent esi tikras (-a), kad tavo prižiūrėjimo komanda gali laiku apdoroti šlamštus ir kenkėjiškas registracijas. + security: + authorized_fetch: Reikalauti tapatybės nustatymo iš federacinių serverių + authorized_fetch_hint: Reikalauti tapatybės nustatymo iš federacinių serverių leidžia griežčiau užtikrinti tiek naudotojo, tiek serverio lygio blokų vykdymą. Tačiau dėl to nukenčia našumas, sumažėja atsakymų pasiekiamumas ir gali kilti suderinamumo su kai kuriomis federacinėmis paslaugomis problemų. Be to, tai nesutrukdys skirtiems dalyviams gauti tavo viešų įrašų ir paskyrų. + authorized_fetch_overridden_hint: Šiuo metu negali pakeisti šio nustatymo, nes jį pakeičia aplinkos kintamasis. + federation_authentication: Federacijos tapatybės nustatymo vykdymas software_updates: description: Rekomenduojama nuolat atnaujinti Mastodon diegyklę, kad galėtum naudotis naujausiais pataisymais ir funkcijomis. Be to, kartais labai svarbu laiku atnaujinti Mastodon, kad būtų išvengta saugumo problemų. Dėl šių priežasčių Mastodon kas 30 minučių tikrina, ar yra naujinimų, ir praneša tau apie tai pagal tavo el. pašto pranešimų parinktis. documentation_link: Sužinoti daugiau @@ -687,34 +701,71 @@ lt: warning: Būkite atsargūs su šia informacija. Niekada jos nesidalinkite! your_token: Tavo prieigos raktas auth: + apply_for_account: Prašyti paskyros + captcha_confirmation: + help_html: Jei turi problemų išsprendžiant CAPTCHA, gali susisiekti su mumis per %{email} ir mes tau padėsime. + hint_html: Dar vienas dalykas! Turime patvirtinti, kad esi žmogus (kad galėtume išvengti šlamšto). Išspręsk toliau pateiktą CAPTCHA ir spausk Tęsti. + title: Saugumo patikrinimas confirmations: + awaiting_review: Tavo el. pašto adresas yra patvirtintas! Domeno %{domain} personalas dabar tikrina tavo registraciją. Jei jie patvirtins tavo paskyrą, gausi el. laišką. + awaiting_review_title: Peržiūrima tavo registracija + clicking_this_link: paspausti šį nuorodą + login_link: prisijungti + proceed_to_login_html: Dabar gali pereiti prie %{login_link}. + redirect_to_app_html: Turėjei būti nukreiptas (-a) į %{app_name} programėlę. Jei taip neatsitiko, pabandyk %{clicking_this_link} arba rankiniu būdu grįžk į programėlę. + registration_complete: Tavo registracija domene %{domain} baigta! welcome_title: Sveiki, %{name}! + wrong_email_hint: Jei šis el. pašto adresas neteisingas, gali jį pakeisti paskyros nustatymuose. delete_account: Ištrinti paskyrą - delete_account_html: Jeigu norite ištrinti savo paskyrą, galite eiti čia. Jūsų prašys patvirtinti pasirinkimą. + delete_account_html: Jei nori ištrinti savo paskyrą, gali tęsti čia. Tavęs bus paprašyta patvirtinimo. description: prefix_invited_by_user: "@%{name} kviečia prisijungti prie šio Mastodon serverio!" - prefix_sign_up: Užsiregistruok Mastodon šiandien! + prefix_sign_up: Užsiregistruok sistemoje Mastodon šiandien! + suffix: Su paskyra galėsi sekti žmones, skelbti naujienas ir keistis žinutėmis su bet kurio Mastodon serverio naudotojais ir dar daugiau! didnt_get_confirmation: Negavai patvirtinimo nuorodos? dont_have_your_security_key: Neturi saugumo rakto? forgot_password: Pamiršai slaptažodį? invalid_reset_password_token: Slaptažodžio atkūrimo raktas yra netinkamas arba nebegaliojantis. Paprašyk naujo. + link_to_otp: Įvesk dvigubą kodą iš telefono arba atkūrimo kodą + link_to_webauth: Naudoti saugumo rakto įrenginį log_in_with: Prisijungti su login: Prisijungti logout: Atsijungti - migrate_account: Prisijungti prie kitos paskyros - migrate_account_html: Jeigu norite nukreipti šią paskyrą į kita, galite tai konfiguruoti čia. + migrate_account: Persikelti prie kitos paskyros + migrate_account_html: Jei nori šią paskyrą nukreipti į kitą, gali sukonfigūruoti ją čia. or_log_in_with: Arba prisijungti su + privacy_policy_agreement_html: Perskaičiau ir sutinku su privatumo politika + progress: + confirm: Patvirtinti el. paštą + details: Tavo duomenys + review: Mūsų peržiūra + rules: Priimti taisykles providers: cas: CAS saml: SAML register: Užsiregistruoti - reset_password: Atstatyti slaptažodį + registration_closed: "%{instance} nepriima naujų narių" + resend_confirmation: Iš naujo siųsti patvirtinimo nuorodą + reset_password: Nustatyti iš naujo slaptažodį rules: + accept: Priimti + back: Grįžti invited_by: 'Gali prisijungti prie %{domain} pagal kvietimą, kurį gavai iš:' + preamble: Tai nustatė ir taiko %{domain} prižiūrėtojai. preamble_invited: Prieš tęsiant, atsižvelk į pagrindines taisykles, kurias nustatė %{domain} prižiūrėtojai. + title: Kelios pagrindinės taisyklės. title_invited: Esi pakviestas. security: Apsauga set_new_password: Nustatyti naują slaptažodį + setup: + email_below_hint_html: Patikrink šlamšto aplanką arba paprašyk kito. Gali ištaisyti savo el. pašto adresą, jei jis neteisingas. + email_settings_hint_html: Spustelėk mūsų atsiųstą nuorodą, kad patikrintum %{email}. Mes lauksime čia. + link_not_received: Negavai nuorodos? + new_confirmation_instructions_sent: Po kelių minučių gausi naują el. laišką su patvirtinimo nuoroda! + title: Patikrinti pašto dėžutę + sign_in: + preamble_html: Prisijunk su savo %{domain} kredencialais. Jei tavo yra kitame serveryje, čia prisijungti negalėsi. + title: Prisijungti prie %{domain} status: account_status: Paskyros būsena redirecting_to: Tavo paskyra yra neaktyvi, nes šiuo metu ji nukreipiama į %{acct}. @@ -851,6 +902,12 @@ lt: expires_at: Baigsis uses: Naudojimai title: Kviesti žmones + login_activities: + authentication_methods: + otp: dvigubas tapatybės nustatymo programėlė + description_html: Jei pastebėjei neatpažįstamą veiklą, apsvarstyk galimybę pakeisti slaptažodį ir įjungti dvigubą tapatybės nustatymą. + empty: Tapatybės nustatymas istorijos nėra + title: Tapatybės nustatymo istorija media_attachments: validations: images_and_video: Negalima pridėti video prie statuso, kuris jau turi nuotrauką @@ -893,6 +950,10 @@ lt: billion: mlrd. million: mln. thousand: tūkst. + otp_authentication: + code_hint: Įvesk autentifikatoriaus programėlės sugeneruotą kodą, kad patvirtintum + description_html: Jei įjungsi dvigubo tapatybės nustatymą naudojant autentifikatoriaus programėlę, prisijungiant reikės turėti telefoną, kuris generuos prieigos raktos, kuriuos turėsi įvesti. + instructions_html: "Nuskenuok šį QR kodą į Google Authenticator arba panašią TOTP programėlę savo telefone. Nuo šiol ši programėlė generuos prieigos raktus, kuriuos turėsi įvesti prisijungiant." pagination: newer: Naujesnis next: Kitas @@ -963,6 +1024,7 @@ lt: revoke: Naikinti revoke_success: Seansas sėkmingai panaikintas. title: Seansai + view_authentication_history: Peržiūrėti paskyros tapatybės nustatymo istoriją settings: account: Paskyra account_settings: Paskyros nustatymai @@ -982,7 +1044,7 @@ lt: profile: Viešas profilis relationships: Sekimai ir sekėjai severed_relationships: Nutrūkę sąryšiai - two_factor_authentication: Dviejų veiksnių autentikacija + two_factor_authentication: Dvigubas tapatybės nustatymas severed_relationships: download: Atsisiųsti (%{count}) preamble: Užblokavus domeną arba prižiūrėtojams nusprendus pristabdyti nuotolinio serverio veiklą, gali prarasti sekimus ir sekėjus. Kai taip atsitiks, galėsi atsisiųsti nutrauktų sąryšių sąrašus, kad juos patikrinti ir galbūt importuoti į kitą serverį. @@ -1035,10 +1097,12 @@ lt: two_factor_authentication: add: Pridėti disable: Išjungti 2FA - enabled: Dviejų veiksnių autentikacija įjungta - enabled_success: Dviejų veiksnių autentikacija sėkmingai įjungta + disabled_success: Dvigubas tapatybės nustatymas sėkmingai išjungtas + enabled: Dvigubas tapatybės nustatymas įjungtas + enabled_success: Dvigubas tapatybės nustatymas sėkmingai įjungtas generate_recovery_codes: Sugeneruoti atkūrimo kodus lost_recovery_codes: Atkūrimo kodai jums leidžia atgauti prisijungimą prie Jūsų paskyros, jeigu prarandate telefoną. Jeigu praradote atkūrimo kodus, juos galite sugeneruoti čia. Jūsų senieji atkūrimo kodai nebeveiks. + otp: Autentifikatoriaus programėlė recovery_codes: Atsarginio atkūrimo kodai recovery_codes_regenerated: Atkūrimo kodai sėkmingai sugeneruoti recovery_instructions_html: Jeigu prarandate prieiga prie telefono, jūs galite naudoti atkūrimo kodus esančius žemiau, kad atgautumėte priega prie savo paskyros.Laikykite atkūrimo kodus saugiai Pavyzdžiui, galite norėti juos išspausdinti, ir laikyti kartu su kitais svarbiais dokumentais. @@ -1055,11 +1119,15 @@ lt: title: Archyvas išimtas failed_2fa: details: 'Štai išsami informacija apie bandymą prisijungti:' - explanation: Kažkas bandė prisijungti prie tavo paskyros, bet nurodė netinkamą antrąjį tapatybės nustatymo veiksnį. + explanation: Kažkas bandė prisijungti prie tavo paskyros, bet nurodė netinkamą dvigubą tapatybės nustatymą. further_actions_html: Jei tai buvo ne tu, rekomenduojame nedelsiant imtis %{action}, nes jis gali būti pažeistas. - subject: Antrojo veiksnio tapatybės nustatymas nesėkmingai - title: Nepavyko atlikti antrojo veiksnio tapatybės nustatymo + subject: Dvigubas tapatybės nustatymas nesėkmingai + title: Nepavyko atlikti dvigubo tapatybės nustatymo + suspicious_sign_in: + further_actions_html: Jei tai buvai ne tu, rekomenduojame nedelsiant %{action} ir įjungti dvigubą tapatybės nustatymą, kad tavo paskyra būtų saugi. warning: + categories: + spam: Šlamštas subject: disable: Jūsų paskyra %{acct} buvo užšaldyta none: Įspėjmas vartotojui %{acct} @@ -1134,3 +1202,4 @@ lt: success: Tavo saugumo raktas buvo sėkmingai ištrintas. nickname_hint: Įvesk naujojo saugumo rakto slapyvardį not_enabled: Dar neįjungei WebAuthn + otp_required: Norint naudoti saugumo raktus, pirmiausia įjunk dvigubą tapatybės nustatymą. diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index 51329edd88..d3237762ea 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -53,7 +53,7 @@ ia: password: Usa al minus 8 characteres phrase: Sera concordate ignorante majuscule/minuscule in le texto o avisos de contento de un message scopes: A que APIs sera permittite acceder al application. Si tu selige un ambito de maxime nivello, tu non besonia de seliger los singulemente. - setting_aggregate_reblogs: Non monstra nove stimulos pro messages que ha essite recentemente stimulate (stimulos solo affice los novemente recipite) + setting_aggregate_reblogs: Non monstrar nove impulsos pro messages que ha essite recentemente impulsate (affecta solmente le impulsos novemente recipite) setting_always_send_emails: Normalmente le avisos de email non sera inviate quando tu activemente usa Mastodon setting_default_sensitive: Le medios sensibile es celate de ordinario e pote esser revelate con un clic setting_display_media_default: Celar le medios marcate como sensibile @@ -81,7 +81,7 @@ ia: backups_retention_period: Le usatores pote generar archivos de lor messages pro discargar los plus tarde. Quando predefinite a un valor positive, iste archivos sera automaticamente delite de tu immagazinage post le specificate numero de dies. bootstrap_timeline_accounts: Iste contos sera appunctate al summitate del recommendationes a sequer del nove usatores. closed_registrations_message: Monstrate quando le inscriptiones es claudite - content_cache_retention_period: Tote messages de altere servitores (includite stimulos e responsas) sera delite post le specificate numero de dies, sin considerar alcun interaction de usator local con ille messages. Isto include messages ubi un usator local los ha marcate como marcapaginas o favoritos. Mentiones private inter usatores de differente instantias sera alsi perdite e impossibile a restaurar. Le uso de iste parametros es intendite pro specific instantias e infringe multe expectationes de usator quando implementate pro uso general. + content_cache_retention_period: Tote le messages de altere servitores (includite impulsos e responsas) essera delite post le numero de dies specificate, independentemente de tote interaction de usatores local con ille messages. Isto include le messages addite al marcapaginas o marcate como favorite per un usator local. Le mentiones private inter usatores de differente instantias tamben essera irrecuperabilemente perdite. Le uso de iste parametro es intendite pro instantias con scopos specific e viola multe expectationes de usatores si es implementate pro uso general. custom_css: Tu pote applicar stilos personalisate sur le version de web de Mastodon. favicon: WEBP, PNG, GIF o JPG. Supplanta le favicone predefinite de Mastodon con un icone personalisate. mascot: Illo substitue le illustration in le interfacie web avantiate. @@ -125,9 +125,9 @@ ia: webauthn: Si illo es un clave USB cura de inserer lo e, si necessari, tocca lo. settings: indexable: Tu pagina del profilo pote apparer in resultatos del recerca sur Google, Bing, e alteros. - show_application: Tu sempre sera capace totevia de vider que app publicava tu message. + show_application: In omne caso, tu potera sempre vider qual app ha publicate tu message. tag: - name: Tu pote solo cambiar le inveloppe del litteras, per exemplo, pro render lo plus legibile + name: Tu pote solmente cambiar le litteras inter majusculas e minusculas, per exemplo, pro render lo plus legibile user: chosen_languages: Si marcate, solo le messages in le linguas seligite sera monstrate in chronologias public role: Le rolo controla que permissos ha le usator @@ -203,10 +203,10 @@ ia: password: Contrasigno phrase: Parola o phrase clave setting_advanced_layout: Activar le interfacie web avantiate - setting_aggregate_reblogs: Gruppa promotiones in classificationes temporal + setting_aggregate_reblogs: Gruppar impulsos in chronologias setting_always_send_emails: Sempre inviar notificationes per e-mail setting_auto_play_gif: Auto-reproduce GIFs animate - setting_boost_modal: Monstrar dialogo de confirmation ante promover + setting_boost_modal: Monstrar dialogo de confirmation ante de impulsar setting_default_language: Lingua de publication setting_default_privacy: Confidentialitate del messages setting_default_sensitive: Sempre marcar le medios cmo sensbile @@ -292,7 +292,7 @@ ia: follow_request: Alcuno requireva de sequer te mention: Alcuno te mentionava pending_account: Nove conto besonia de revision - reblog: Alcuno promoveva tu message + reblog: Alcuno ha impulsate tu message report: Un nove reporto es inviate software_updates: all: Notificar sur tote le actualisationes From a22865a352cca312a50556fd38ce2d5764ecc4dc Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 31 May 2024 05:35:56 -0400 Subject: [PATCH 281/658] Add `:email` to filter parameter logging config (#30492) --- config/initializers/filter_parameter_logging.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index a119afa124..e88b020ff3 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -6,5 +6,5 @@ # Use this to limit dissemination of sensitive information. # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. Rails.application.config.filter_parameters += [ - :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn + :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn ] From 4d047b95aed493bc29e36b6958bfe362607507c6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 31 May 2024 05:54:11 -0400 Subject: [PATCH 282/658] Use more direct attribute handling in `User` fabricator (#30495) --- spec/fabricators/user_fabricator.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/fabricators/user_fabricator.rb b/spec/fabricators/user_fabricator.rb index 9031d5cd04..0df7caea60 100644 --- a/spec/fabricators/user_fabricator.rb +++ b/spec/fabricators/user_fabricator.rb @@ -1,7 +1,12 @@ # frozen_string_literal: true Fabricator(:user) do - account { Fabricate.build(:account, user: nil) } + account do |attrs| + Fabricate.build( + :account, + attrs.fetch(:account_attributes, {}).merge(user: nil) + ) + end email { sequence(:email) { |i| "#{i}#{Faker::Internet.email}" } } password '123456789' confirmed_at { Time.zone.now } From 64d69eb95b7f149d10c03059f8c79b24499f461d Mon Sep 17 00:00:00 2001 From: Shlee Date: Fri, 31 May 2024 23:26:43 +1000 Subject: [PATCH 283/658] Change default ruby version to 3.3.2 (#30478) --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4278242bc9..6a5d400686 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,22 +7,22 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} -# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.1"] -ARG RUBY_VERSION="3.3.1" +# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"] +ARG RUBY_VERSION="3.3.2" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] ARG NODE_MAJOR_VERSION="20" # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] ARG DEBIAN_VERSION="bookworm" # Node image to use for base image based on combined variables (ex: 20-bookworm-slim) FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node -# Ruby image to use for base image based on combined variables (ex: 3.3.1-slim-bookworm) +# Ruby image to use for base image based on combined variables (ex: 3.3.x-slim-bookworm) FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA # Example: v4.2.0-nightly.2023.11.09+something # Overwrite existence of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"] ARG MASTODON_VERSION_PRERELEASE="" -# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"] +# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="PR-12345"] ARG MASTODON_VERSION_METADATA="" # Allow Ruby on Rails to serve static files From e20a57909e4d39401f410ca1811adf2357092687 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 13:29:37 +0000 Subject: [PATCH 284/658] chore(deps): update dependency propshaft to v0.9.0 (#30382) 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 33053948c5..c62c57dcc2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -597,7 +597,7 @@ GEM net-smtp premailer (~> 1.7, >= 1.7.9) private_address_check (0.5.0) - propshaft (0.8.0) + propshaft (0.9.0) actionpack (>= 7.0.0) activesupport (>= 7.0.0) rack From d326ad0ed9a2e874213c9313f25b973638e4b94d Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 31 May 2024 17:18:51 +0200 Subject: [PATCH 285/658] Revert "Change default ruby version to 3.3.2 (#30478)" (#30506) --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6a5d400686..4278242bc9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,22 +7,22 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} -# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"] -ARG RUBY_VERSION="3.3.2" +# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.1"] +ARG RUBY_VERSION="3.3.1" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] ARG NODE_MAJOR_VERSION="20" # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] ARG DEBIAN_VERSION="bookworm" # Node image to use for base image based on combined variables (ex: 20-bookworm-slim) FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node -# Ruby image to use for base image based on combined variables (ex: 3.3.x-slim-bookworm) +# Ruby image to use for base image based on combined variables (ex: 3.3.1-slim-bookworm) FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA # Example: v4.2.0-nightly.2023.11.09+something # Overwrite existence of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"] ARG MASTODON_VERSION_PRERELEASE="" -# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="PR-12345"] +# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"] ARG MASTODON_VERSION_METADATA="" # Allow Ruby on Rails to serve static files From 4d3748ac447c7e43fcfcc36ffcd4f97afeeead46 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 3 Jun 2024 03:16:01 -0400 Subject: [PATCH 286/658] Fix rack attack `match_type` value typo in logging config (#30514) --- config/initializers/rack_attack_logging.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/rack_attack_logging.rb b/config/initializers/rack_attack_logging.rb index 458bc799f9..65b89e6029 100644 --- a/config/initializers/rack_attack_logging.rb +++ b/config/initializers/rack_attack_logging.rb @@ -3,7 +3,7 @@ ActiveSupport::Notifications.subscribe(/rack_attack/) do |_name, _start, _finish, _request_id, payload| req = payload[:request] - next unless [:throttle, :blacklist].include? req.env['rack.attack.match_type'] + next unless [:throttle, :blocklist].include? req.env['rack.attack.match_type'] Rails.logger.info("Rate limit hit (#{req.env['rack.attack.match_type']}): #{req.ip} #{req.request_method} #{req.fullpath}") end From 469de923aa568dd96a6358445fc98870f7f08755 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 3 Jun 2024 03:16:29 -0400 Subject: [PATCH 287/658] Update `current_user` override mode description in controllers (#30515) --- .../api/v1/instances/extended_descriptions_controller.rb | 2 +- app/controllers/api/v1/instances/peers_controller.rb | 2 +- app/controllers/api/v1/instances/rules_controller.rb | 2 +- app/controllers/api/v1/instances_controller.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/instances/extended_descriptions_controller.rb b/app/controllers/api/v1/instances/extended_descriptions_controller.rb index 73d2248117..db3d082f61 100644 --- a/app/controllers/api/v1/instances/extended_descriptions_controller.rb +++ b/app/controllers/api/v1/instances/extended_descriptions_controller.rb @@ -5,7 +5,7 @@ class Api::V1::Instances::ExtendedDescriptionsController < Api::V1::Instances::B before_action :set_extended_description - # Override `current_user` to avoid reading session cookies unless in whitelist mode + # Override `current_user` to avoid reading session cookies unless in limited federation mode def current_user super if limited_federation_mode? end diff --git a/app/controllers/api/v1/instances/peers_controller.rb b/app/controllers/api/v1/instances/peers_controller.rb index 83116472bb..fac763b405 100644 --- a/app/controllers/api/v1/instances/peers_controller.rb +++ b/app/controllers/api/v1/instances/peers_controller.rb @@ -5,7 +5,7 @@ class Api::V1::Instances::PeersController < Api::V1::Instances::BaseController skip_around_action :set_locale - # Override `current_user` to avoid reading session cookies unless in whitelist mode + # Override `current_user` to avoid reading session cookies unless in limited federation mode def current_user super if limited_federation_mode? end diff --git a/app/controllers/api/v1/instances/rules_controller.rb b/app/controllers/api/v1/instances/rules_controller.rb index d240d72464..3930eec0dd 100644 --- a/app/controllers/api/v1/instances/rules_controller.rb +++ b/app/controllers/api/v1/instances/rules_controller.rb @@ -5,7 +5,7 @@ class Api::V1::Instances::RulesController < Api::V1::Instances::BaseController before_action :set_rules - # Override `current_user` to avoid reading session cookies unless in whitelist mode + # Override `current_user` to avoid reading session cookies unless in limited federation mode def current_user super if limited_federation_mode? end diff --git a/app/controllers/api/v1/instances_controller.rb b/app/controllers/api/v1/instances_controller.rb index df4a14af15..49da75ed28 100644 --- a/app/controllers/api/v1/instances_controller.rb +++ b/app/controllers/api/v1/instances_controller.rb @@ -6,7 +6,7 @@ class Api::V1::InstancesController < Api::BaseController vary_by '' - # Override `current_user` to avoid reading session cookies unless in whitelist mode + # Override `current_user` to avoid reading session cookies unless in limited federation mode def current_user super if limited_federation_mode? end From aa9b80f57d1fb1f1b75abb28db3f915829f6b9f9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 09:34:33 +0200 Subject: [PATCH 288/658] New Crowdin Translations (automated) (#30517) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/lv.json | 6 ++--- app/javascript/mastodon/locales/mr.json | 5 ++++ config/locales/doorkeeper.lv.yml | 1 + config/locales/ia.yml | 32 ++++++++++++------------- config/locales/simple_form.lv.yml | 5 ++++ 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 7a1d583d9a..efc45c9c08 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -175,7 +175,7 @@ "confirmations.discard_edit_media.message": "Ir nesaglabātas izmaiņas informācijas nesēja aprakstā vai priekšskatījumā. Vēlies tās atmest tik un tā?", "confirmations.domain_block.message": "Vai tu tiešām vēlies bloķēt visu domēnu {domain}? Parasti pietiek, ja nobloķē vai apklusini kādu. Tu neredzēsi saturu vai paziņojumus no šī domēna nevienā laika līnijā. Tavi sekotāji no šī domēna tiks noņemti.", "confirmations.edit.confirm": "Labot", - "confirmations.edit.message": "Rediģējot, tiks pārrakstīts ziņojums, kuru tu šobrīd raksti. Vai tiešām vēlies turpināt?", + "confirmations.edit.message": "Labošana pārrakstīs ziņojumu, kas šobrīd tiek sastādīts. Vai tiešām turpināt?", "confirmations.logout.confirm": "Iziet", "confirmations.logout.message": "Vai tiešām vēlies izrakstīties?", "confirmations.mute.confirm": "Apklusināt", @@ -447,7 +447,7 @@ "notification.relationships_severance_event": "Zaudēti savienojumi ar {name}", "notification.relationships_severance_event.learn_more": "Uzzināt vairāk", "notification.status": "{name} tikko publicēja", - "notification.update": "{name} rediģēja ierakstu", + "notification.update": "{name} laboja ierakstu", "notification_requests.accept": "Pieņemt", "notification_requests.dismiss": "Noraidīt", "notification_requests.notifications_from": "Paziņojumi no {name}", @@ -663,7 +663,7 @@ "status.direct_indicator": "Pieminēts privāti", "status.edit": "Labot", "status.edited": "Pēdējoreiz labots {date}", - "status.edited_x_times": "Labots {count, plural, one {{count} reizi} other {{count} reizes}}", + "status.edited_x_times": "Labots {count, plural, zero {{count} reižu} one {{count} reizi} other {{count} reizes}}", "status.embed": "Iegult", "status.favourite": "Izlasē", "status.favourites": "{count, plural, zero {izlasēs} one {izlasē} other {izlasēs}}", diff --git a/app/javascript/mastodon/locales/mr.json b/app/javascript/mastodon/locales/mr.json index a00b39e838..c07294d90a 100644 --- a/app/javascript/mastodon/locales/mr.json +++ b/app/javascript/mastodon/locales/mr.json @@ -17,9 +17,12 @@ "account.badges.group": "गट", "account.block": "@{name} यांना ब्लॉक करा", "account.block_domain": "{domain} पासून सर्व लपवा", + "account.block_short": "अवरोध", "account.blocked": "ब्लॉक केले आहे", "account.browse_more_on_origin_server": "मूळ प्रोफाइलवर अधिक ब्राउझ करा", "account.cancel_follow_request": "फॉलो विनंती मागे घ्या", + "account.copy": "दुवा कॉपी करा", + "account.direct": "खाजगीरित्या उल्लेखीत @{name}", "account.disable_notifications": "जेव्हा @{name} पोस्ट करतात तेव्हा मला सूचित करणे थांबवा", "account.domain_blocked": "Domain hidden", "account.edit_profile": "प्रोफाइल एडिट करा", @@ -29,6 +32,7 @@ "account.featured_tags.last_status_never": "पोस्ट नाहीत", "account.featured_tags.title": "{name} चे वैशिष्ट्यीकृत हॅशटॅग", "account.follow": "अनुयायी व्हा", + "account.follow_back": "आपणही अनुसरण करा", "account.followers": "अनुयायी", "account.followers.empty": "ह्या वापरकर्त्याचा आतापर्यंत कोणी अनुयायी नाही.", "account.followers_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", @@ -45,6 +49,7 @@ "account.mention": "@{name} चा उल्लेख करा", "account.moved_to": "{name} ने सूचित केले आहे की त्यांचे नवीन खाते आता आहे:", "account.mute": "@{name} ला मूक कारा", + "account.mute_short": "नि:शब्द", "account.muted": "मौन", "account.open_original_page": "मूळ पृष्ठ उघडा", "account.posts": "Toots", diff --git a/config/locales/doorkeeper.lv.yml b/config/locales/doorkeeper.lv.yml index 5aa5daef3f..2005ce3c79 100644 --- a/config/locales/doorkeeper.lv.yml +++ b/config/locales/doorkeeper.lv.yml @@ -174,6 +174,7 @@ lv: read:filters: apskatīt savus filtrus read:follows: apskatīt savus sekotājus read:lists: apskatīt savus sarakstus + read:me: lasīt tikai Tava konta pamatinformāciju read:mutes: apskatīt savus apklusinātos read:notifications: apskatīt savus paziņojumus read:reports: apskatīt savus pārskatus diff --git a/config/locales/ia.yml b/config/locales/ia.yml index f8834136b9..ab1f674fd8 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -38,7 +38,7 @@ ia: avatar: Avatar by_domain: Dominio change_email: - changed_msg: Email cambiate con successo! + changed_msg: E-mail cambiate con successo! current_email: E-mail actual label: Cambiar e-mail new_email: Nove e-mail @@ -56,12 +56,12 @@ ia: delete: Deler datos deleted: Delite demote: Degradar - destroyed_msg: Le datos de %{username} ora es in cauda pro su imminente deletion + destroyed_msg: Le datos de %{username} es ora in cauda pro lor imminente deletion disable: Gelar disable_sign_in_token_auth: Disactivar le authentication per token in e-mail - disable_two_factor_authentication: Disactivar 2FA + disable_two_factor_authentication: Disactivar authentication bifactorial disabled: Gelate - display_name: Nomine visibile + display_name: Nomine a monstrar domain: Dominio edit: Modificar email: E-mail @@ -82,7 +82,7 @@ ia: all: Toto local: Local remote: Remote - title: Location + title: Position login_status: Stato de session media_attachments: Annexos multimedial memorialize: Render commemorative @@ -137,7 +137,7 @@ ia: security: Securitate security_measures: only_password: Solmente contrasigno - password_and_2fa: Contrasigno e 2FA + password_and_2fa: Contrasigno e A2F sensitive: Fortiar sensibile sensitized: Marcate como sensibile shared_inbox_url: URL del cassa de entrata condividite @@ -195,17 +195,17 @@ ia: destroy_email_domain_block: Crear blocada de dominio email destroy_instance: Purgar dominio destroy_ip_block: Deler le regula IP - destroy_status: Deler le message - destroy_unavailable_domain: Deler le dominio non disponibile + destroy_status: Deler message + destroy_unavailable_domain: Deler dominio indisponibile destroy_user_role: Destruer rolo - disable_2fa_user: Disactivar 2FA + disable_2fa_user: Disactivar A2F disable_custom_emoji: Disactivar emoji personalisate - disable_sign_in_token_auth_user: Disactivar le authentication per testimonio via email pro usator + disable_sign_in_token_auth_user: Disactivar le authentication per token de e-mail pro le usator disable_user: Disactivar le usator enable_custom_emoji: Activar emoji personalisate - enable_sign_in_token_auth_user: Activar le authentication per testimonio via email pro usator + enable_sign_in_token_auth_user: Activar le authentication per token de e-mail pro le usator enable_user: Activar le usator - memorialize_account: Commemorar conto + memorialize_account: Converter conto in memorial promote_user: Promover usator reject_appeal: Rejectar appello reject_user: Rejectar usator @@ -214,14 +214,14 @@ ia: resend_user: Reinviar message de confirmation reset_password_user: Reinitialisar contrasigno resolve_report: Resolver reporto - sensitive_account: Marcar como sensibile le medios del conto + sensitive_account: Fortiar de marcar le conto como sensibile silence_account: Limitar conto suspend_account: Suspender conto unassigned_report: Disassignar reporto unblock_email_account: Disblocar adresse de e-mail - unsensitive_account: Dismarcar como sensibile le medios del conto - unsilence_account: Disfacer le limite de conto - unsuspend_account: Annullar suspension de conto + unsensitive_account: Non plus fortiar de marcar le conto como sensibile + unsilence_account: Non plus limitar conto + unsuspend_account: Non plus suspender conto update_announcement: Actualisar annuncio update_custom_emoji: Actualisar emoji personalisate update_domain_block: Actualisar blocada de dominio diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml index 711484b642..888e08b650 100644 --- a/config/locales/simple_form.lv.yml +++ b/config/locales/simple_form.lv.yml @@ -77,9 +77,11 @@ lv: warn: Paslēp filtrēto saturu aiz brīdinājuma, kurā minēts filtra nosaukums form_admin_settings: activity_api_enabled: Vietēji publicēto ziņu, aktīvo lietotāju un jauno reģistrāciju skaits nedēļas kopās + app_icon: WEBP, PNG, GIF vai JPG. Mobilajās ierīcēs aizstāj noklusējuma lietotnes ikonu ar pielāgotu. bootstrap_timeline_accounts: Šie konti tiks piesprausti jauno lietotāju ieteikumu augšdaļā. closed_registrations_message: Tiek rādīts, kad reģistrēšanās ir slēgta custom_css: Vari lietot pielāgotus stilus Mastodon tīmekļa versijā. + favicon: WEBP, PNG, GIF vai JPG. Aizstāj noklusējuma Mastodon favikonu ar pielāgotu. mascot: Ignorē ilustrāciju uzlabotajā tīmekļa saskarnē. peers_api_enabled: Domēna vārdu saraksts, ar kuriem šis serveris ir saskāries fediversā. Šeit nav iekļauti dati par to, vai tu veic federāciju ar noteiktu serveri, tikai tavs serveris par to zina. To izmanto dienesti, kas apkopo statistiku par federāciju vispārīgā nozīmē. profile_directory: Profilu direktorijā ir uzskaitīti visi lietotāji, kuri ir izvēlējušies būt atklājami. @@ -113,6 +115,7 @@ lv: sign_up_requires_approval: Jaunām reģistrācijām būs nepieciešams tavs apstiprinājums severity: Izvēlies, kas notiks ar pieprasījumiem no šīs IP adreses rule: + hint: Izvēles. Sniedz vairāk informācijas par nosacījumu text: Apraksti nosacījumus vai prasības šī servera lietotājiem. Centies, lai tas būtu īss un vienkāršs sessions: otp: 'Ievadi divfaktoru kodu, ko ģenerējusi tava tālruņa lietotne, vai izmanto kādu no atkopšanas kodiem:' @@ -239,6 +242,7 @@ lv: backups_retention_period: Lietotāja arhīva glabāšanas periods bootstrap_timeline_accounts: Vienmēr iesaki šos kontus jaunajiem lietotājiem closed_registrations_message: Pielāgots ziņojums, ja reģistrēšanās nav pieejama + content_cache_retention_period: Attālā satura paturēšanas laika posms custom_css: Pielāgots CSS mascot: Pielāgots talismans (mantots) media_cache_retention_period: Multivides kešatmiņas saglabāšanas periods @@ -295,6 +299,7 @@ lv: patch: Paziņot par novērsto kļūdu atjauninājumiem trending_tag: Jaunā tendence ir jāpārskata rule: + hint: Papildu informācija text: Noteikumi settings: indexable: Ietvert profila lapu meklēšanas dzinējos From 6e92a9b73e9093a85679841081d60a143261050d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 09:35:06 +0200 Subject: [PATCH 289/658] chore(deps): update devdependencies (non-major) (#30526) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 60 ++++++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/yarn.lock b/yarn.lock index f77dedd4b4..46a55e3f48 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8380,12 +8380,12 @@ __metadata: languageName: node linkType: hard -"file-entry-cache@npm:^8.0.0": - version: 8.0.0 - resolution: "file-entry-cache@npm:8.0.0" +"file-entry-cache@npm:^9.0.0": + version: 9.0.0 + resolution: "file-entry-cache@npm:9.0.0" dependencies: - flat-cache: "npm:^4.0.0" - checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 + flat-cache: "npm:^5.0.0" + checksum: 10c0/07b0a4f062dc0aa258f3e1b06ac083ea25313f5e289943e146fafdaf3315dcc031635545eea7fe98fe5598b91d6c7f48dba7a251dd7ac20108a6ebf7d00b0b1c languageName: node linkType: hard @@ -8530,14 +8530,13 @@ __metadata: languageName: node linkType: hard -"flat-cache@npm:^4.0.0": - version: 4.0.0 - resolution: "flat-cache@npm:4.0.0" +"flat-cache@npm:^5.0.0": + version: 5.0.0 + resolution: "flat-cache@npm:5.0.0" dependencies: - flatted: "npm:^3.2.9" + flatted: "npm:^3.3.1" keyv: "npm:^4.5.4" - rimraf: "npm:^5.0.5" - checksum: 10c0/8f99e27bb3de94e91e7b4ca5120488cdc2b7f8cd952a538f1a566101963057eb42ca318e9fac0d36987dcca34316ff04b61c1dc3dcc8084f6f5e801a52a8e547 + checksum: 10c0/847f25eefec5d6614fdce76dc6097ee98f63fd4dfbcb908718905ac56610f939f4c28b1f908d6e8857d49286fe73235095d2e7ac9df096c35a3e8a15204c361b languageName: node linkType: hard @@ -8550,10 +8549,10 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^3.2.9": - version: 3.2.9 - resolution: "flatted@npm:3.2.9" - checksum: 10c0/5c91c5a0a21bbc0b07b272231e5b4efe6b822bcb4ad317caf6bb06984be4042a9e9045026307da0fdb4583f1f545e317a67ef1231a59e71f7fced3cc429cfc53 +"flatted@npm:^3.2.9, flatted@npm:^3.3.1": + version: 3.3.1 + resolution: "flatted@npm:3.3.1" + checksum: 10c0/324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf languageName: node linkType: hard @@ -8877,7 +8876,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.2.6, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.2.2, glob@npm:^10.2.6, glob@npm:^10.3.10": version: 10.4.1 resolution: "glob@npm:10.4.1" dependencies: @@ -11719,7 +11718,7 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.4, micromatch@npm:^4.0.5, micromatch@npm:~4.0.7": +"micromatch@npm:^4.0.4, micromatch@npm:^4.0.7, micromatch@npm:~4.0.7": version: 4.0.7 resolution: "micromatch@npm:4.0.7" dependencies: @@ -13965,11 +13964,11 @@ __metadata: linkType: hard "prettier@npm:^3.0.0": - version: 3.2.5 - resolution: "prettier@npm:3.2.5" + version: 3.3.0 + resolution: "prettier@npm:3.3.0" bin: prettier: bin/prettier.cjs - checksum: 10c0/ea327f37a7d46f2324a34ad35292af2ad4c4c3c3355da07313339d7e554320f66f65f91e856add8530157a733c6c4a897dc41b577056be5c24c40f739f5ee8c6 + checksum: 10c0/d033c356320aa2e468bf29c931b094ac730d2f4defd5eb2989d8589313dec901d2fc866e3788f3d161e420b142ea4ec3dda535dbe0169ef4d0026397a68ba9cf languageName: node linkType: hard @@ -15165,17 +15164,6 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^5.0.5": - version: 5.0.5 - resolution: "rimraf@npm:5.0.5" - dependencies: - glob: "npm:^10.3.7" - bin: - rimraf: dist/esm/bin.mjs - checksum: 10c0/d50dbe724f33835decd88395b25ed35995077c60a50ae78ded06e0185418914e555817aad1b4243edbff2254548c2f6ad6f70cc850040bebb4da9e8cc016f586 - languageName: node - linkType: hard - "ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": version: 2.0.2 resolution: "ripemd160@npm:2.0.2" @@ -16436,8 +16424,8 @@ __metadata: linkType: hard "stylelint@npm:^16.0.2": - version: 16.6.0 - resolution: "stylelint@npm:16.6.0" + version: 16.6.1 + resolution: "stylelint@npm:16.6.1" dependencies: "@csstools/css-parser-algorithms": "npm:^2.6.3" "@csstools/css-tokenizer": "npm:^2.3.1" @@ -16452,7 +16440,7 @@ __metadata: debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" fastest-levenshtein: "npm:^1.0.16" - file-entry-cache: "npm:^8.0.0" + file-entry-cache: "npm:^9.0.0" global-modules: "npm:^2.0.0" globby: "npm:^11.1.0" globjoin: "npm:^0.1.4" @@ -16463,7 +16451,7 @@ __metadata: known-css-properties: "npm:^0.31.0" mathml-tag-names: "npm:^2.1.3" meow: "npm:^13.2.0" - micromatch: "npm:^4.0.5" + micromatch: "npm:^4.0.7" normalize-path: "npm:^3.0.0" picocolors: "npm:^1.0.1" postcss: "npm:^8.4.38" @@ -16480,7 +16468,7 @@ __metadata: write-file-atomic: "npm:^5.0.1" bin: stylelint: bin/stylelint.mjs - checksum: 10c0/acfb7983a0b71677d066b2aa570eefdac0a7be2e21351bac8884b8156deaeec19e53ad128ae7ae7933c79f6045f1de8d759ba06cfbc373b2711015860805a3e7 + checksum: 10c0/8dc9b0024d6fb109380a142171ab8a134c3863aa8b8736f0083310a0d05f173dcda5680f29267697dfa0aaeb2f08aef4ef113e4bb4f8582fcfdd97f35be51d71 languageName: node linkType: hard From db49b0e5e92e1bb54a579b407b1bf9bcee6d4e4e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 09:35:11 +0200 Subject: [PATCH 290/658] chore(deps): update eslint (non-major) (#30527) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 486 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 271 insertions(+), 215 deletions(-) diff --git a/yarn.lock b/yarn.lock index 46a55e3f48..162f0cb359 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2131,9 +2131,9 @@ __metadata: languageName: node linkType: hard -"@es-joy/jsdoccomment@npm:~0.43.0": - version: 0.43.0 - resolution: "@es-joy/jsdoccomment@npm:0.43.0" +"@es-joy/jsdoccomment@npm:~0.43.1": + version: 0.43.1 + resolution: "@es-joy/jsdoccomment@npm:0.43.1" dependencies: "@types/eslint": "npm:^8.56.5" "@types/estree": "npm:^1.0.5" @@ -2141,7 +2141,7 @@ __metadata: comment-parser: "npm:1.4.1" esquery: "npm:^1.5.0" jsdoc-type-pratt-parser: "npm:~4.0.0" - checksum: 10c0/862294ed89772a231f309edd68405ece00f6aaf43103210f28410da894a6b697bc1f281c59e813dd37d5b7294f633ee7b874e07a0aa3d72f49504089fc9cb2c4 + checksum: 10c0/2a4842b0e37eb937d55e3028ab2cd7ece7097e1f8c878bb9e28c3309371844688c2869d25bb949e2664c9ba63e388ea09b769c9f42f77515d328ec40e6fcfed1 languageName: node linkType: hard @@ -4109,14 +4109,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^7.0.0": - version: 7.10.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.10.0" + version: 7.11.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.11.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.10.0" - "@typescript-eslint/type-utils": "npm:7.10.0" - "@typescript-eslint/utils": "npm:7.10.0" - "@typescript-eslint/visitor-keys": "npm:7.10.0" + "@typescript-eslint/scope-manager": "npm:7.11.0" + "@typescript-eslint/type-utils": "npm:7.11.0" + "@typescript-eslint/utils": "npm:7.11.0" + "@typescript-eslint/visitor-keys": "npm:7.11.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -4127,25 +4127,25 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/bf3f0118ea5961c3eb01894678246458a329d82dda9ac7c2f5bfe77896410d05a08a4655e533bcb1ed2a3132ba6421981ec8c2ed0a3545779d9603ea231947ae + checksum: 10c0/50fedf832e4de9546569106eab1d10716204ceebc5cc7d62299112c881212270d0f7857e3d6452c07db031d40b58cf27c4d1b1a36043e8e700fc3496e377b54a languageName: node linkType: hard "@typescript-eslint/parser@npm:^7.0.0": - version: 7.10.0 - resolution: "@typescript-eslint/parser@npm:7.10.0" + version: 7.11.0 + resolution: "@typescript-eslint/parser@npm:7.11.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.10.0" - "@typescript-eslint/types": "npm:7.10.0" - "@typescript-eslint/typescript-estree": "npm:7.10.0" - "@typescript-eslint/visitor-keys": "npm:7.10.0" + "@typescript-eslint/scope-manager": "npm:7.11.0" + "@typescript-eslint/types": "npm:7.11.0" + "@typescript-eslint/typescript-estree": "npm:7.11.0" + "@typescript-eslint/visitor-keys": "npm:7.11.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/4c4fbf43b5b05d75b766acb803d3dd078c6e080641a77f9e48ba005713466738ea4a71f0564fa3ce520988d65158d14c8c952ba01ccbc431ab4a05935db5ce6d + checksum: 10c0/f5d1343fae90ccd91aea8adf194e22ed3eb4b2ea79d03d8a9ca6e7b669a6db306e93138ec64f7020c5b3128619d50304dea1f06043eaff6b015071822cad4972 languageName: node linkType: hard @@ -4159,22 +4159,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/scope-manager@npm:7.10.0" +"@typescript-eslint/scope-manager@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/scope-manager@npm:7.11.0" dependencies: - "@typescript-eslint/types": "npm:7.10.0" - "@typescript-eslint/visitor-keys": "npm:7.10.0" - checksum: 10c0/1d4f7ee137b95bd423b5a1b0d03251202dfc19bd8b6adfa5ff5df25fd5aa30e2d8ca50ab0d8d2e92441670ecbc2a82b3c2dbe39a4f268ec1ee1c1e267f7fd1d1 + "@typescript-eslint/types": "npm:7.11.0" + "@typescript-eslint/visitor-keys": "npm:7.11.0" + checksum: 10c0/35f9d88f38f2366017b15c9ee752f2605afa8009fa1eaf81c8b2b71fc22ddd2a33fff794a02015c8991a5fa99f315c3d6d76a5957d3fad1ccbb4cd46735c98b5 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/type-utils@npm:7.10.0" +"@typescript-eslint/type-utils@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/type-utils@npm:7.11.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.10.0" - "@typescript-eslint/utils": "npm:7.10.0" + "@typescript-eslint/typescript-estree": "npm:7.11.0" + "@typescript-eslint/utils": "npm:7.11.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependencies: @@ -4182,7 +4182,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/55e9a6690f9cedb79d30abb1990b161affaa2684dac246b743223353812c9c1e3fd2d923c67b193c6a3624a07e1c82c900ce7bf5b6b9891c846f04cb480ebd9f + checksum: 10c0/637395cb0f4c424c610e751906a31dcfedcdbd8c479012da6e81f9be6b930f32317bfe170ccb758d93a411b2bd9c4e7e5d18892094466099c6f9c3dceda81a72 languageName: node linkType: hard @@ -4193,10 +4193,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.10.0, @typescript-eslint/types@npm:^7.2.0": - version: 7.10.0 - resolution: "@typescript-eslint/types@npm:7.10.0" - checksum: 10c0/f01d9330b93cc362ba7967ab5037396f64742076450e1f93139fa69cbe93a6ece3ed55d68ab780c9b7d07ef4a7c645da410305216a2cfc5dec7eba49ee65ab23 +"@typescript-eslint/types@npm:7.11.0, @typescript-eslint/types@npm:^7.2.0": + version: 7.11.0 + resolution: "@typescript-eslint/types@npm:7.11.0" + checksum: 10c0/c5d6c517124017eb44aa180c8ea1fad26ec8e47502f92fd12245ba3141560e69d7f7e35b8aa160ddd5df63a2952af407e2f62cc58b663c86e1f778ffb5b01789 languageName: node linkType: hard @@ -4219,12 +4219,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.10.0" +"@typescript-eslint/typescript-estree@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.11.0" dependencies: - "@typescript-eslint/types": "npm:7.10.0" - "@typescript-eslint/visitor-keys": "npm:7.10.0" + "@typescript-eslint/types": "npm:7.11.0" + "@typescript-eslint/visitor-keys": "npm:7.11.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -4234,21 +4234,21 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/6200695834c566e52e2fa7331f1a05019f7815969d8c1e1e237b85a99664d36f41ccc16384eff3f8582a0ecb75f1cc315b56ee9283b818da37f24fa4d42f1d7a + checksum: 10c0/a4eda43f352d20edebae0c1c221c4fd9de0673a94988cf1ae3f5e4917ef9cdb9ead8d3673ea8dd6e80d9cf3523a47c295be1326a3fae017b277233f4c4b4026b languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/utils@npm:7.10.0" +"@typescript-eslint/utils@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/utils@npm:7.11.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:7.10.0" - "@typescript-eslint/types": "npm:7.10.0" - "@typescript-eslint/typescript-estree": "npm:7.10.0" + "@typescript-eslint/scope-manager": "npm:7.11.0" + "@typescript-eslint/types": "npm:7.11.0" + "@typescript-eslint/typescript-estree": "npm:7.11.0" peerDependencies: eslint: ^8.56.0 - checksum: 10c0/6724471f94f2788f59748f7efa2a3a53ea910099993bee2fa5746ab5acacecdc9fcb110c568b18099ddc946ea44919ed394bff2bd055ba81fc69f5e6297b73bf + checksum: 10c0/539a7ff8b825ad810fc59a80269094748df1a397a42cdbb212c493fc2486711c7d8fd6d75d4cd8a067822b8e6a11f42c50441977d51c183eec47992506d1cdf8 languageName: node linkType: hard @@ -4279,13 +4279,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.10.0" +"@typescript-eslint/visitor-keys@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.11.0" dependencies: - "@typescript-eslint/types": "npm:7.10.0" + "@typescript-eslint/types": "npm:7.11.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/049e812bcd28869059d04c7bf3543bb55f5205f468b777439c4f120417fb856fb6024cb1d25291aa12556bd08e84f043a96d754ffb2cde37abb604d6f3c51634 + checksum: 10c0/664e558d9645896484b7ffc9381837f0d52443bf8d121a5586d02d42ca4d17dc35faf526768c4b1beb52c57c43fae555898eb087651eb1c7a3d60f1085effea1 languageName: node linkType: hard @@ -4829,16 +4829,17 @@ __metadata: languageName: node linkType: hard -"array-includes@npm:^3.1.6, array-includes@npm:^3.1.7": - version: 3.1.7 - resolution: "array-includes@npm:3.1.7" +"array-includes@npm:^3.1.6, array-includes@npm:^3.1.7, array-includes@npm:^3.1.8": + version: 3.1.8 + resolution: "array-includes@npm:3.1.8" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - get-intrinsic: "npm:^1.2.1" + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.4" is-string: "npm:^1.0.7" - checksum: 10c0/692907bd7f19d06dc58ccb761f34b58f5dc0b437d2b47a8fe42a1501849a5cf5c27aed3d521a9702667827c2c85a7e75df00a402c438094d87fc43f39ebf9b2b + checksum: 10c0/5b1004d203e85873b96ddc493f090c9672fd6c80d7a60b798da8a14bff8a670ff95db5aafc9abc14a211943f05220dacf8ea17638ae0af1a6a47b8c0b48ce370 languageName: node linkType: hard @@ -4872,16 +4873,17 @@ __metadata: languageName: node linkType: hard -"array.prototype.findlast@npm:^1.2.4": - version: 1.2.4 - resolution: "array.prototype.findlast@npm:1.2.4" +"array.prototype.findlast@npm:^1.2.5": + version: 1.2.5 + resolution: "array.prototype.findlast@npm:1.2.5" dependencies: - call-bind: "npm:^1.0.5" + call-bind: "npm:^1.0.7" define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.22.3" + es-abstract: "npm:^1.23.2" es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/4b5145a68ebaa00ef3d61de07c6694cad73d60763079f1e7662b948e5a167b5121b0c1e6feae8df1e42ead07c21699e25242b95cd5c48e094fd530b192aa4150 + checksum: 10c0/ddc952b829145ab45411b9d6adcb51a8c17c76bf89c9dd64b52d5dffa65d033da8c076ed2e17091779e83bc892b9848188d7b4b33453c5565e65a92863cb2775 languageName: node linkType: hard @@ -5065,15 +5067,6 @@ __metadata: languageName: node linkType: hard -"asynciterator.prototype@npm:^1.0.0": - version: 1.0.0 - resolution: "asynciterator.prototype@npm:1.0.0" - dependencies: - has-symbols: "npm:^1.0.3" - checksum: 10c0/fb76850e57d931ff59fd16b6cddb79b0d34fe45f400b2c3480d38892e72cd089787401687dbdb7cdb14ece402c275d3e02a648760d1489cd493527129c4c6204 - languageName: node - linkType: hard - "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" @@ -5122,7 +5115,7 @@ __metadata: languageName: node linkType: hard -"available-typed-arrays@npm:^1.0.6, available-typed-arrays@npm:^1.0.7": +"available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" dependencies: @@ -5808,7 +5801,7 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7": +"call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7": version: 1.0.7 resolution: "call-bind@npm:1.0.7" dependencies: @@ -6868,6 +6861,39 @@ __metadata: languageName: node linkType: hard +"data-view-buffer@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-buffer@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.6" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10c0/8984119e59dbed906a11fcfb417d7d861936f16697a0e7216fe2c6c810f6b5e8f4a5281e73f2c28e8e9259027190ac4a33e2a65fdd7fa86ac06b76e838918583 + languageName: node + linkType: hard + +"data-view-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-byte-length@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10c0/b7d9e48a0cf5aefed9ab7d123559917b2d7e0d65531f43b2fd95b9d3a6b46042dd3fca597c42bba384e66b70d7ad66ff23932f8367b241f53d93af42cfe04ec2 + languageName: node + linkType: hard + +"data-view-byte-offset@npm:^1.0.0": + version: 1.0.0 + resolution: "data-view-byte-offset@npm:1.0.0" + dependencies: + call-bind: "npm:^1.0.6" + es-errors: "npm:^1.3.0" + is-data-view: "npm:^1.0.1" + checksum: 10c0/21b0d2e53fd6e20cc4257c873bf6d36d77bd6185624b84076c0a1ddaa757b49aaf076254006341d35568e89f52eecd1ccb1a502cfb620f2beca04f48a6a62a8f + languageName: node + linkType: hard + "dateformat@npm:^4.6.3": version: 4.6.3 resolution: "dateformat@npm:4.6.3" @@ -6983,7 +7009,7 @@ __metadata: languageName: node linkType: hard -"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.2": +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.2, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" dependencies: @@ -7541,16 +7567,20 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.17.2, es-abstract@npm:^1.20.4, es-abstract@npm:^1.21.2, es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3, es-abstract@npm:^1.22.4": - version: 1.22.5 - resolution: "es-abstract@npm:1.22.5" +"es-abstract@npm:^1.17.2, es-abstract@npm:^1.20.4, es-abstract@npm:^1.21.2, es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3": + version: 1.23.3 + resolution: "es-abstract@npm:1.23.3" dependencies: array-buffer-byte-length: "npm:^1.0.1" arraybuffer.prototype.slice: "npm:^1.0.3" available-typed-arrays: "npm:^1.0.7" call-bind: "npm:^1.0.7" + data-view-buffer: "npm:^1.0.1" + data-view-byte-length: "npm:^1.0.1" + data-view-byte-offset: "npm:^1.0.0" es-define-property: "npm:^1.0.0" es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" es-set-tostringtag: "npm:^2.0.3" es-to-primitive: "npm:^1.2.1" function.prototype.name: "npm:^1.1.6" @@ -7561,10 +7591,11 @@ __metadata: has-property-descriptors: "npm:^1.0.2" has-proto: "npm:^1.0.3" has-symbols: "npm:^1.0.3" - hasown: "npm:^2.0.1" + hasown: "npm:^2.0.2" internal-slot: "npm:^1.0.7" is-array-buffer: "npm:^3.0.4" is-callable: "npm:^1.2.7" + is-data-view: "npm:^1.0.1" is-negative-zero: "npm:^2.0.3" is-regex: "npm:^1.1.4" is-shared-array-buffer: "npm:^1.0.3" @@ -7575,18 +7606,18 @@ __metadata: object-keys: "npm:^1.1.1" object.assign: "npm:^4.1.5" regexp.prototype.flags: "npm:^1.5.2" - safe-array-concat: "npm:^1.1.0" + safe-array-concat: "npm:^1.1.2" safe-regex-test: "npm:^1.0.3" - string.prototype.trim: "npm:^1.2.8" - string.prototype.trimend: "npm:^1.0.7" - string.prototype.trimstart: "npm:^1.0.7" + string.prototype.trim: "npm:^1.2.9" + string.prototype.trimend: "npm:^1.0.8" + string.prototype.trimstart: "npm:^1.0.8" typed-array-buffer: "npm:^1.0.2" typed-array-byte-length: "npm:^1.0.1" typed-array-byte-offset: "npm:^1.0.2" - typed-array-length: "npm:^1.0.5" + typed-array-length: "npm:^1.0.6" unbox-primitive: "npm:^1.0.2" - which-typed-array: "npm:^1.1.14" - checksum: 10c0/4bca5a60f0dff6c0a5690d8e51374cfcb8760d5dbbb1069174b4d41461cf4e0c3e0c1993bccbc5aa0799ff078199f1bcde2122b8709e0d17c2beffafff01010a + which-typed-array: "npm:^1.1.15" + checksum: 10c0/d27e9afafb225c6924bee9971a7f25f20c314f2d6cb93a63cada4ac11dcf42040896a6c22e5fb8f2a10767055ed4ddf400be3b1eb12297d281726de470b75666 languageName: node linkType: hard @@ -7613,30 +7644,38 @@ __metadata: languageName: node linkType: hard -"es-iterator-helpers@npm:^1.0.15, es-iterator-helpers@npm:^1.0.17": - version: 1.0.17 - resolution: "es-iterator-helpers@npm:1.0.17" +"es-iterator-helpers@npm:^1.0.15, es-iterator-helpers@npm:^1.0.19": + version: 1.0.19 + resolution: "es-iterator-helpers@npm:1.0.19" dependencies: - asynciterator.prototype: "npm:^1.0.0" call-bind: "npm:^1.0.7" define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.22.4" + es-abstract: "npm:^1.23.3" es-errors: "npm:^1.3.0" - es-set-tostringtag: "npm:^2.0.2" + es-set-tostringtag: "npm:^2.0.3" function-bind: "npm:^1.1.2" get-intrinsic: "npm:^1.2.4" globalthis: "npm:^1.0.3" has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.0.1" + has-proto: "npm:^1.0.3" has-symbols: "npm:^1.0.3" internal-slot: "npm:^1.0.7" iterator.prototype: "npm:^1.1.2" - safe-array-concat: "npm:^1.1.0" - checksum: 10c0/d0f281257e7165f068fd4fc3beb63d07ae4f18fbef02a2bbe4a39272b764164c1ce3311ae7c5429ac30003aef290fcdf569050e4a9ba3560e044440f68e9a47c + safe-array-concat: "npm:^1.1.2" + checksum: 10c0/ae8f0241e383b3d197383b9842c48def7fce0255fb6ed049311b686ce295595d9e389b466f6a1b7d4e7bb92d82f5e716d6fae55e20c1040249bf976743b038c5 languageName: node linkType: hard -"es-set-tostringtag@npm:^2.0.2, es-set-tostringtag@npm:^2.0.3": +"es-object-atoms@npm:^1.0.0": + version: 1.0.0 + resolution: "es-object-atoms@npm:1.0.0" + dependencies: + es-errors: "npm:^1.3.0" + checksum: 10c0/1fed3d102eb27ab8d983337bb7c8b159dd2a1e63ff833ec54eea1311c96d5b08223b433060ba240541ca8adba9eee6b0a60cdbf2f80634b784febc9cc8b687b4 + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.0.3": version: 2.0.3 resolution: "es-set-tostringtag@npm:2.0.3" dependencies: @@ -7817,20 +7856,20 @@ __metadata: linkType: hard "eslint-plugin-jsdoc@npm:^48.0.0": - version: 48.2.6 - resolution: "eslint-plugin-jsdoc@npm:48.2.6" + version: 48.2.7 + resolution: "eslint-plugin-jsdoc@npm:48.2.7" dependencies: - "@es-joy/jsdoccomment": "npm:~0.43.0" + "@es-joy/jsdoccomment": "npm:~0.43.1" 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" - semver: "npm:^7.6.1" + semver: "npm:^7.6.2" spdx-expression-parse: "npm:^4.0.0" peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: 10c0/9f01b3000aa31f17767786c62caf62f1e8c4b88bfef04b207d3b1de785be287cc2da3ad16ed32afacd5f6e6a9b76ebf3369069be416ce2228c44cd6d084fcd8f + checksum: 10c0/74d0f95b3d880dd4221dbc0b9341266a6cce3b8ca8d3e30032223af3552364643d6b82ad733d9bc06a20f0d640f21e4d8f5a4b00901d1771572625178b8c40c3 languageName: node linkType: hard @@ -7879,30 +7918,30 @@ __metadata: linkType: hard "eslint-plugin-react@npm:^7.33.2": - version: 7.34.1 - resolution: "eslint-plugin-react@npm:7.34.1" + version: 7.34.2 + resolution: "eslint-plugin-react@npm:7.34.2" dependencies: - array-includes: "npm:^3.1.7" - array.prototype.findlast: "npm:^1.2.4" + array-includes: "npm:^3.1.8" + array.prototype.findlast: "npm:^1.2.5" array.prototype.flatmap: "npm:^1.3.2" array.prototype.toreversed: "npm:^1.1.2" array.prototype.tosorted: "npm:^1.1.3" doctrine: "npm:^2.1.0" - es-iterator-helpers: "npm:^1.0.17" + es-iterator-helpers: "npm:^1.0.19" estraverse: "npm:^5.3.0" jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.7" - object.fromentries: "npm:^2.0.7" - object.hasown: "npm:^1.1.3" - object.values: "npm:^1.1.7" + object.entries: "npm:^1.1.8" + object.fromentries: "npm:^2.0.8" + object.hasown: "npm:^1.1.4" + object.values: "npm:^1.2.0" prop-types: "npm:^15.8.1" resolve: "npm:^2.0.0-next.5" semver: "npm:^6.3.1" - string.prototype.matchall: "npm:^4.0.10" + string.prototype.matchall: "npm:^4.0.11" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: 10c0/7c61b1314d37a4ac2f2474f9571f801f1a1a5d81dcd4abbb5d07145406518722fb792367267757ee116bde254be9753242d6b93c9619110398b3fe1746e4848c + checksum: 10c0/37dc04424da8626f20a071466e7238d53ed111c53e5e5398d813ac2cf76a2078f00d91f7833fe5b2f0fc98f2688a75b36e78e9ada9f1068705d23c7031094316 languageName: node linkType: hard @@ -8771,7 +8810,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": +"get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" dependencies: @@ -9091,7 +9130,7 @@ __metadata: languageName: node linkType: hard -"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.1, has-tostringtag@npm:^1.0.2": +"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.2": version: 1.0.2 resolution: "has-tostringtag@npm:1.0.2" dependencies: @@ -9160,12 +9199,12 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.0, hasown@npm:^2.0.1": - version: 2.0.1 - resolution: "hasown@npm:2.0.1" +"hasown@npm:^2.0.0, hasown@npm:^2.0.1, hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" dependencies: function-bind: "npm:^1.1.2" - checksum: 10c0/9e27e70e8e4204f4124c8f99950d1ba2b1f5174864fd39ff26da190f9ea6488c1b3927dcc64981c26d1f637a971783c9489d62c829d393ea509e6f1ba20370bb + checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 languageName: node linkType: hard @@ -9610,7 +9649,7 @@ __metadata: languageName: node linkType: hard -"internal-slot@npm:^1.0.5, internal-slot@npm:^1.0.7": +"internal-slot@npm:^1.0.7": version: 1.0.7 resolution: "internal-slot@npm:1.0.7" dependencies: @@ -9842,6 +9881,15 @@ __metadata: languageName: node linkType: hard +"is-data-view@npm:^1.0.1": + version: 1.0.1 + resolution: "is-data-view@npm:1.0.1" + dependencies: + is-typed-array: "npm:^1.1.13" + checksum: 10c0/a3e6ec84efe303da859107aed9b970e018e2bee7ffcb48e2f8096921a493608134240e672a2072577e5f23a729846241d9634806e8a0e51d9129c56d5f65442d + languageName: node + linkType: hard + "is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.5": version: 1.0.5 resolution: "is-date-object@npm:1.0.5" @@ -12299,7 +12347,7 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.13.1, object-inspect@npm:^1.9.0": +"object-inspect@npm:^1.13.1": version: 1.13.1 resolution: "object-inspect@npm:1.13.1" checksum: 10c0/fad603f408e345c82e946abdf4bfd774260a5ed3e5997a0b057c44153ac32c7271ff19e3a5ae39c858da683ba045ccac2f65245c12763ce4e8594f818f4a648d @@ -12344,25 +12392,26 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.7": - version: 1.1.7 - resolution: "object.entries@npm:1.1.7" +"object.entries@npm:^1.1.7, object.entries@npm:^1.1.8": + version: 1.1.8 + resolution: "object.entries@npm:1.1.8" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - checksum: 10c0/3ad1899cc7bf14546bf28f4a9b363ae8690b90948fcfbcac4c808395435d760f26193d9cae95337ce0e3c1e5c1f4fa45f7b46b31b68d389e9e117fce38775d86 + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/db9ea979d2956a3bc26c262da4a4d212d36f374652cc4c13efdd069c1a519c16571c137e2893d1c46e1cb0e15c88fd6419eaf410c945f329f09835487d7e65d3 languageName: node linkType: hard -"object.fromentries@npm:^2.0.7": - version: 2.0.7 - resolution: "object.fromentries@npm:2.0.7" +"object.fromentries@npm:^2.0.7, object.fromentries@npm:^2.0.8": + version: 2.0.8 + resolution: "object.fromentries@npm:2.0.8" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - checksum: 10c0/071745c21f6fc9e6c914691f2532c1fb60ad967e5ddc52801d09958b5de926566299d07ae14466452a7efd29015f9145d6c09c573d93a0dc6f1683ee0ec2b93b + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/cd4327e6c3369cfa805deb4cbbe919bfb7d3aeebf0bcaba291bb568ea7169f8f8cdbcabe2f00b40db0c20cd20f08e11b5f3a5a36fb7dd3fe04850c50db3bf83b languageName: node linkType: hard @@ -12391,13 +12440,14 @@ __metadata: languageName: node linkType: hard -"object.hasown@npm:^1.1.3": - version: 1.1.3 - resolution: "object.hasown@npm:1.1.3" +"object.hasown@npm:^1.1.4": + version: 1.1.4 + resolution: "object.hasown@npm:1.1.4" dependencies: - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - checksum: 10c0/8a41ba4fb1208a85c2275e9b5098071beacc24345b9a71ab98ef0a1c61b34dc74c6b460ff1e1884c33843d8f2553df64a10eec2b74b3ed009e3b2710c826bd2c + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/f23187b08d874ef1aea060118c8259eb7f99f93c15a50771d710569534119062b90e087b92952b2d0fb1bb8914d61fb0b43c57fb06f622aaad538fe6868ab987 languageName: node linkType: hard @@ -12410,14 +12460,14 @@ __metadata: languageName: node linkType: hard -"object.values@npm:^1.1.0, object.values@npm:^1.1.6, object.values@npm:^1.1.7": - version: 1.1.7 - resolution: "object.values@npm:1.1.7" +"object.values@npm:^1.1.0, object.values@npm:^1.1.6, object.values@npm:^1.1.7, object.values@npm:^1.2.0": + version: 1.2.0 + resolution: "object.values@npm:1.2.0" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - checksum: 10c0/e869d6a37fb7afdd0054dea49036d6ccebb84854a8848a093bbd1bc516f53e690bba88f0bc3e83fdfa74c601469ee6989c9b13359cda9604144c6e732fad3b6b + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/15809dc40fd6c5529501324fec5ff08570b7d70fb5ebbe8e2b3901afec35cf2b3dc484d1210c6c642cd3e7e0a5e18dd1d6850115337fef46bdae14ab0cb18ac3 languageName: node linkType: hard @@ -14868,7 +14918,7 @@ __metadata: languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.2.0, regexp.prototype.flags@npm:^1.5.0, regexp.prototype.flags@npm:^1.5.2": +"regexp.prototype.flags@npm:^1.2.0, regexp.prototype.flags@npm:^1.5.2": version: 1.5.2 resolution: "regexp.prototype.flags@npm:1.5.2" dependencies: @@ -15211,15 +15261,15 @@ __metadata: languageName: node linkType: hard -"safe-array-concat@npm:^1.0.0, safe-array-concat@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-array-concat@npm:1.1.0" +"safe-array-concat@npm:^1.0.0, safe-array-concat@npm:^1.1.2": + version: 1.1.2 + resolution: "safe-array-concat@npm:1.1.2" dependencies: - call-bind: "npm:^1.0.5" - get-intrinsic: "npm:^1.2.2" + call-bind: "npm:^1.0.7" + get-intrinsic: "npm:^1.2.4" has-symbols: "npm:^1.0.3" isarray: "npm:^2.0.5" - checksum: 10c0/833d3d950fc7507a60075f9bfaf41ec6dac7c50c7a9d62b1e6b071ecc162185881f92e594ff95c1a18301c881352dd6fd236d56999d5819559db7b92da9c28af + checksum: 10c0/12f9fdb01c8585e199a347eacc3bae7b5164ae805cdc8c6707199dbad5b9e30001a50a43c4ee24dc9ea32dbb7279397850e9208a7e217f4d8b1cf5d90129dec9 languageName: node linkType: hard @@ -15418,7 +15468,7 @@ __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, semver@npm:^7.6.0, semver@npm:^7.6.1": +"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, semver@npm:^7.6.2": version: 7.6.2 resolution: "semver@npm:7.6.2" bin: @@ -15514,14 +15564,15 @@ __metadata: languageName: node linkType: hard -"set-function-name@npm:^2.0.0, set-function-name@npm:^2.0.1": - version: 2.0.1 - resolution: "set-function-name@npm:2.0.1" +"set-function-name@npm:^2.0.1, set-function-name@npm:^2.0.2": + version: 2.0.2 + resolution: "set-function-name@npm:2.0.2" dependencies: - define-data-property: "npm:^1.0.1" + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" functions-have-names: "npm:^1.2.3" - has-property-descriptors: "npm:^1.0.0" - checksum: 10c0/6be7d3e15be47f4db8a5a563a35c60b5e7c4af91cc900e8972ffad33d3aaa227900faa55f60121cdb04b85866a734bb7fe4cd91f654c632861cc86121a48312a + has-property-descriptors: "npm:^1.0.2" + checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 languageName: node linkType: hard @@ -15618,14 +15669,15 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.0.4": - version: 1.0.4 - resolution: "side-channel@npm:1.0.4" +"side-channel@npm:^1.0.4, side-channel@npm:^1.0.6": + version: 1.0.6 + resolution: "side-channel@npm:1.0.6" dependencies: - call-bind: "npm:^1.0.0" - get-intrinsic: "npm:^1.0.2" - object-inspect: "npm:^1.9.0" - checksum: 10c0/054a5d23ee35054b2c4609b9fd2a0587760737782b5d765a9c7852264710cc39c6dcb56a9bbd6c12cd84071648aea3edb2359d2f6e560677eedadce511ac1da5 + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.4" + object-inspect: "npm:^1.13.1" + checksum: 10c0/d2afd163dc733cc0a39aa6f7e39bf0c436293510dbccbff446733daeaf295857dbccf94297092ec8c53e2503acac30f0b78830876f0485991d62a90e9cad305f languageName: node linkType: hard @@ -16161,53 +16213,57 @@ __metadata: languageName: node linkType: hard -"string.prototype.matchall@npm:^4.0.10, string.prototype.matchall@npm:^4.0.6": - version: 4.0.10 - resolution: "string.prototype.matchall@npm:4.0.10" +"string.prototype.matchall@npm:^4.0.11, string.prototype.matchall@npm:^4.0.6": + version: 4.0.11 + resolution: "string.prototype.matchall@npm:4.0.11" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - get-intrinsic: "npm:^1.2.1" + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.4" + gopd: "npm:^1.0.1" has-symbols: "npm:^1.0.3" - internal-slot: "npm:^1.0.5" - regexp.prototype.flags: "npm:^1.5.0" - set-function-name: "npm:^2.0.0" - side-channel: "npm:^1.0.4" - checksum: 10c0/cd7495fb0de16d43efeee3887b98701941f3817bd5f09351ad1825b023d307720c86394d56d56380563d97767ab25bf5448db239fcecbb85c28e2180f23e324a + internal-slot: "npm:^1.0.7" + regexp.prototype.flags: "npm:^1.5.2" + set-function-name: "npm:^2.0.2" + side-channel: "npm:^1.0.6" + checksum: 10c0/915a2562ac9ab5e01b7be6fd8baa0b2b233a0a9aa975fcb2ec13cc26f08fb9a3e85d5abdaa533c99c6fc4c5b65b914eba3d80c4aff9792a4c9fed403f28f7d9d languageName: node linkType: hard -"string.prototype.trim@npm:^1.2.8": - version: 1.2.8 - resolution: "string.prototype.trim@npm:1.2.8" +"string.prototype.trim@npm:^1.2.9": + version: 1.2.9 + resolution: "string.prototype.trim@npm:1.2.9" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - checksum: 10c0/4f76c583908bcde9a71208ddff38f67f24c9ec8093631601666a0df8b52fad44dad2368c78895ce83eb2ae8e7068294cc96a02fc971ab234e4d5c9bb61ea4e34 + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.0" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/dcef1a0fb61d255778155006b372dff8cc6c4394bc39869117e4241f41a2c52899c0d263ffc7738a1f9e61488c490b05c0427faa15151efad721e1a9fb2663c2 languageName: node linkType: hard -"string.prototype.trimend@npm:^1.0.7": - version: 1.0.7 - resolution: "string.prototype.trimend@npm:1.0.7" +"string.prototype.trimend@npm:^1.0.8": + version: 1.0.8 + resolution: "string.prototype.trimend@npm:1.0.8" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - checksum: 10c0/53c24911c7c4d8d65f5ef5322de23a3d5b6b4db73273e05871d5ab4571ae5638f38f7f19d71d09116578fb060e5a145cc6a208af2d248c8baf7a34f44d32ce57 + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/0a0b54c17c070551b38e756ae271865ac6cc5f60dabf2e7e343cceae7d9b02e1a1120a824e090e79da1b041a74464e8477e2da43e2775c85392be30a6f60963c languageName: node linkType: hard -"string.prototype.trimstart@npm:^1.0.7": - version: 1.0.7 - resolution: "string.prototype.trimstart@npm:1.0.7" +"string.prototype.trimstart@npm:^1.0.8": + version: 1.0.8 + resolution: "string.prototype.trimstart@npm:1.0.8" dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.22.1" - checksum: 10c0/0bcf391b41ea16d4fda9c9953d0a7075171fe090d33b4cf64849af94944c50862995672ac03e0c5dba2940a213ad7f53515a668dac859ce22a0276289ae5cf4f + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/d53af1899959e53c83b64a5fd120be93e067da740e7e75acb433849aa640782fb6c7d4cd5b84c954c84413745a3764df135a8afeb22908b86a835290788d8366 languageName: node linkType: hard @@ -17061,9 +17117,9 @@ __metadata: languageName: node linkType: hard -"typed-array-length@npm:^1.0.5": - version: 1.0.5 - resolution: "typed-array-length@npm:1.0.5" +"typed-array-length@npm:^1.0.6": + version: 1.0.6 + resolution: "typed-array-length@npm:1.0.6" dependencies: call-bind: "npm:^1.0.7" for-each: "npm:^0.3.3" @@ -17071,7 +17127,7 @@ __metadata: has-proto: "npm:^1.0.3" is-typed-array: "npm:^1.1.13" possible-typed-array-names: "npm:^1.0.0" - checksum: 10c0/5cc0f79196e70a92f8f40846cfa62b3de6be51e83f73655e137116cf65e3c29a288502b18cc8faf33c943c2470a4569009e1d6da338441649a2db2f135761ad5 + checksum: 10c0/74253d7dc488eb28b6b2711cf31f5a9dcefc9c41b0681fd1c178ed0a1681b4468581a3626d39cd4df7aee3d3927ab62be06aa9ca74e5baf81827f61641445b77 languageName: node linkType: hard @@ -17931,16 +17987,16 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.9": - version: 1.1.14 - resolution: "which-typed-array@npm:1.1.14" +"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.9": + version: 1.1.15 + resolution: "which-typed-array@npm:1.1.15" dependencies: - available-typed-arrays: "npm:^1.0.6" - call-bind: "npm:^1.0.5" + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" for-each: "npm:^0.3.3" gopd: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.1" - checksum: 10c0/0960f1e77807058819451b98c51d4cd72031593e8de990b24bd3fc22e176f5eee22921d68d852297c786aec117689f0423ed20aa4fde7ce2704d680677891f56 + has-tostringtag: "npm:^1.0.2" + checksum: 10c0/4465d5348c044032032251be54d8988270e69c6b7154f8fcb2a47ff706fe36f7624b3a24246b8d9089435a8f4ec48c1c1025c5d6b499456b9e5eff4f48212983 languageName: node linkType: hard From 974335e4144eab90a8c5eb91da55d2f8385c68c6 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 3 Jun 2024 10:35:59 +0200 Subject: [PATCH 291/658] Add experimental server-side notification grouping (#29889) --- .../api/v2_alpha/notifications_controller.rb | 91 ++++++++++ app/models/notification.rb | 62 +++++++ app/models/notification_group.rb | 29 ++++ .../rest/notification_group_serializer.rb | 45 +++++ app/services/notify_service.rb | 22 +++ config/application.rb | 2 + config/routes/api.rb | 12 ++ ...13095755_add_group_key_to_notifications.rb | 7 + ...tifications_on_account_id_and_group_key.rb | 9 + db/schema.rb | 2 + lib/active_record/with_recursive.rb | 65 +++++++ lib/arel/union_parenthesizing.rb | 51 ++++++ spec/models/notification_spec.rb | 60 +++++++ .../api/v2_alpha/notifications_spec.rb | 161 ++++++++++++++++++ 14 files changed, 618 insertions(+) create mode 100644 app/controllers/api/v2_alpha/notifications_controller.rb create mode 100644 app/models/notification_group.rb create mode 100644 app/serializers/rest/notification_group_serializer.rb create mode 100644 db/migrate/20240513095755_add_group_key_to_notifications.rb create mode 100644 db/migrate/20240513123807_add_index_notifications_on_account_id_and_group_key.rb create mode 100644 lib/active_record/with_recursive.rb create mode 100644 lib/arel/union_parenthesizing.rb create mode 100644 spec/requests/api/v2_alpha/notifications_spec.rb diff --git a/app/controllers/api/v2_alpha/notifications_controller.rb b/app/controllers/api/v2_alpha/notifications_controller.rb new file mode 100644 index 0000000000..19d3ac9018 --- /dev/null +++ b/app/controllers/api/v2_alpha/notifications_controller.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +class Api::V2Alpha::NotificationsController < Api::BaseController + before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :dismiss] + before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :dismiss] + before_action :require_user! + after_action :insert_pagination_headers, only: :index + + DEFAULT_NOTIFICATIONS_LIMIT = 40 + + def index + with_read_replica do + @notifications = load_notifications + @group_metadata = load_group_metadata + @relationships = StatusRelationshipsPresenter.new(target_statuses_from_notifications, current_user&.account_id) + end + + render json: @notifications.map { |notification| NotificationGroup.from_notification(notification) }, each_serializer: REST::NotificationGroupSerializer, relationships: @relationships, group_metadata: @group_metadata + end + + def show + @notification = current_account.notifications.without_suspended.find_by!(group_key: params[:id]) + render json: NotificationGroup.from_notification(@notification), serializer: REST::NotificationGroupSerializer + end + + def clear + current_account.notifications.delete_all + render_empty + end + + def dismiss + current_account.notifications.where(group_key: params[:id]).destroy_all + render_empty + end + + private + + def load_notifications + notifications = browserable_account_notifications.includes(from_account: [:account_stat, :user]).to_a_grouped_paginated_by_id( + limit_param(DEFAULT_NOTIFICATIONS_LIMIT), + params_slice(:max_id, :since_id, :min_id) + ) + + Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses| + preload_collection(target_statuses, Status) + end + end + + def load_group_metadata + return {} if @notifications.empty? + + browserable_account_notifications + .where(group_key: @notifications.filter_map(&:group_key)) + .where(id: (@notifications.last.id)..(@notifications.first.id)) + .group(:group_key) + .pluck(:group_key, 'min(notifications.id) as min_id', 'max(notifications.id) as max_id', 'max(notifications.created_at) as latest_notification_at') + .to_h { |group_key, min_id, max_id, latest_notification_at| [group_key, { min_id: min_id, max_id: max_id, latest_notification_at: latest_notification_at }] } + end + + def browserable_account_notifications + current_account.notifications.without_suspended.browserable( + types: Array(browserable_params[:types]), + exclude_types: Array(browserable_params[:exclude_types]), + include_filtered: truthy_param?(:include_filtered) + ) + end + + def target_statuses_from_notifications + @notifications.filter_map(&:target_status) + end + + def next_path + api_v2_alpha_notifications_url pagination_params(max_id: pagination_max_id) unless @notifications.empty? + end + + def prev_path + api_v2_alpha_notifications_url pagination_params(min_id: pagination_since_id) unless @notifications.empty? + end + + def pagination_collection + @notifications + end + + def browserable_params + params.permit(:include_filtered, types: [], exclude_types: []) + end + + def pagination_params(core_params) + params.slice(:limit, :types, :exclude_types, :include_filtered).permit(:limit, :include_filtered, types: [], exclude_types: []).merge(core_params) + end +end diff --git a/app/models/notification.rb b/app/models/notification.rb index 7cbab4dc8c..e3deaa5348 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -13,6 +13,7 @@ # from_account_id :bigint(8) not null # type :string # filtered :boolean default(FALSE), not null +# group_key :string # class Notification < ApplicationRecord @@ -136,6 +137,67 @@ class Notification < ApplicationRecord end end + # This returns notifications from the request page, but with at most one notification per group. + # Notifications that have no `group_key` each count as a separate group. + def paginate_groups_by_max_id(limit, max_id: nil, since_id: nil) + query = reorder(id: :desc) + query = query.where(id: ...max_id) if max_id.present? + query = query.where(id: (since_id + 1)...) if since_id.present? + + unscoped + .with_recursive( + grouped_notifications: [ + query + .select('notifications.*', "ARRAY[COALESCE(notifications.group_key, 'ungrouped-' || notifications.id)] groups") + .limit(1), + query + .joins('CROSS JOIN grouped_notifications') + .where('notifications.id < grouped_notifications.id') + .where.not("COALESCE(notifications.group_key, 'ungrouped-' || notifications.id) = ANY(grouped_notifications.groups)") + .select('notifications.*', "array_append(grouped_notifications.groups, COALESCE(notifications.group_key, 'ungrouped-' || notifications.id))") + .limit(1), + ] + ) + .from('grouped_notifications AS notifications') + .order(id: :desc) + .limit(limit) + end + + # Differs from :paginate_groups_by_max_id in that it gives the results immediately following min_id, + # whereas since_id gives the items with largest id, but with since_id as a cutoff. + # Results will be in ascending order by id. + def paginate_groups_by_min_id(limit, max_id: nil, min_id: nil) + query = reorder(id: :asc) + query = query.where(id: (min_id + 1)...) if min_id.present? + query = query.where(id: ...max_id) if max_id.present? + + unscoped + .with_recursive( + grouped_notifications: [ + query + .select('notifications.*', "ARRAY[COALESCE(notifications.group_key, 'ungrouped-' || notifications.id)] groups") + .limit(1), + query + .joins('CROSS JOIN grouped_notifications') + .where('notifications.id > grouped_notifications.id') + .where.not("COALESCE(notifications.group_key, 'ungrouped-' || notifications.id) = ANY(grouped_notifications.groups)") + .select('notifications.*', "array_append(grouped_notifications.groups, COALESCE(notifications.group_key, 'ungrouped-' || notifications.id))") + .limit(1), + ] + ) + .from('grouped_notifications AS notifications') + .order(id: :asc) + .limit(limit) + end + + def to_a_grouped_paginated_by_id(limit, options = {}) + if options[:min_id].present? + paginate_groups_by_min_id(limit, min_id: options[:min_id], max_id: options[:max_id]).reverse + else + paginate_groups_by_max_id(limit, max_id: options[:max_id], since_id: options[:since_id]).to_a + end + end + def preload_cache_collection_target_statuses(notifications, &_block) notifications.group_by(&:type).each do |type, grouped_notifications| associations = TARGET_STATUS_INCLUDES_BY_TYPE[type] diff --git a/app/models/notification_group.rb b/app/models/notification_group.rb new file mode 100644 index 0000000000..07967f9dcb --- /dev/null +++ b/app/models/notification_group.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class NotificationGroup < ActiveModelSerializers::Model + attributes :group_key, :sample_accounts, :notifications_count, :notification + + def self.from_notification(notification) + if notification.group_key.present? + # TODO: caching and preloading + sample_accounts = notification.account.notifications.where(group_key: notification.group_key).order(id: :desc).limit(3).map(&:from_account) + notifications_count = notification.account.notifications.where(group_key: notification.group_key).count + else + sample_accounts = [notification.from_account] + notifications_count = 1 + end + + NotificationGroup.new( + notification: notification, + group_key: notification.group_key || "ungrouped-#{notification.id}", + sample_accounts: sample_accounts, + notifications_count: notifications_count + ) + end + + delegate :type, + :target_status, + :report, + :account_relationship_severance_event, + to: :notification, prefix: false +end diff --git a/app/serializers/rest/notification_group_serializer.rb b/app/serializers/rest/notification_group_serializer.rb new file mode 100644 index 0000000000..6c1d2465d2 --- /dev/null +++ b/app/serializers/rest/notification_group_serializer.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class REST::NotificationGroupSerializer < ActiveModel::Serializer + attributes :group_key, :notifications_count, :type + + attribute :page_min_id, if: :paginated? + attribute :page_max_id, if: :paginated? + attribute :latest_page_notification_at, if: :paginated? + + has_many :sample_accounts, serializer: REST::AccountSerializer + belongs_to :target_status, key: :status, if: :status_type?, serializer: REST::StatusSerializer + belongs_to :report, if: :report_type?, serializer: REST::ReportSerializer + belongs_to :account_relationship_severance_event, key: :event, if: :relationship_severance_event?, serializer: REST::AccountRelationshipSeveranceEventSerializer + + def status_type? + [:favourite, :reblog, :status, :mention, :poll, :update].include?(object.type) + end + + def report_type? + object.type == :'admin.report' + end + + def relationship_severance_event? + object.type == :severed_relationships + end + + def page_min_id + range = instance_options[:group_metadata][object.group_key] + range.present? ? range[:min_id].to_s : object.notification.id.to_s + end + + def page_max_id + range = instance_options[:group_metadata][object.group_key] + range.present? ? range[:max_id].to_s : object.notification.id.to_s + end + + def latest_page_notification_at + range = instance_options[:group_metadata][object.group_key] + range.present? ? range[:latest_notification_at] : object.notification.created_at + end + + def paginated? + instance_options[:group_metadata].present? + end +end diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index 1f01c2d48e..d69b5af141 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -3,6 +3,9 @@ class NotifyService < BaseService include Redisable + MAXIMUM_GROUP_SPAN_HOURS = 12 + MAXIMUM_GROUP_GAP_TIME = 4.hours.to_i + NON_EMAIL_TYPES = %i( admin.report admin.sign_up @@ -183,6 +186,7 @@ class NotifyService < BaseService return if dismiss? @notification.filtered = filter? + @notification.group_key = notification_group_key @notification.save! # It's possible the underlying activity has been deleted @@ -202,6 +206,24 @@ class NotifyService < BaseService private + def notification_group_key + return nil if @notification.filtered || %i(favourite reblog).exclude?(@notification.type) + + type_prefix = "#{@notification.type}-#{@notification.target_status.id}" + redis_key = "notif-group/#{@recipient.id}/#{type_prefix}" + hour_bucket = @notification.activity.created_at.utc.to_i / 1.hour.to_i + + # Reuse previous group if it does not span too large an amount of time + previous_bucket = redis.get(redis_key).to_i + hour_bucket = previous_bucket if hour_bucket < previous_bucket + MAXIMUM_GROUP_SPAN_HOURS + + # Do not track groups past a given inactivity time + # We do not concern ourselves with race conditions since we use hour buckets + redis.set(redis_key, hour_bucket, ex: MAXIMUM_GROUP_GAP_TIME) + + "#{type_prefix}-#{hour_bucket}" + end + def dismiss? DismissCondition.new(@notification).dismiss? end diff --git a/config/application.rb b/config/application.rb index 6d6e91a5cc..a8e313069d 100644 --- a/config/application.rb +++ b/config/application.rb @@ -51,6 +51,8 @@ require_relative '../lib/rails/engine_extensions' require_relative '../lib/action_dispatch/remote_ip_extensions' require_relative '../lib/active_record/database_tasks_extensions' require_relative '../lib/active_record/batches' +require_relative '../lib/active_record/with_recursive' +require_relative '../lib/arel/union_parenthesizing' require_relative '../lib/simple_navigation/item_extensions' Bundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true' diff --git a/config/routes/api.rb b/config/routes/api.rb index bf3cee0c10..135a19a0a7 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -327,6 +327,18 @@ namespace :api, format: false do end end + namespace :v2_alpha do + resources :notifications, only: [:index, :show] do + collection do + post :clear + end + + member do + post :dismiss + end + end + end + namespace :web do resource :settings, only: [:update] resources :embeds, only: [:show] diff --git a/db/migrate/20240513095755_add_group_key_to_notifications.rb b/db/migrate/20240513095755_add_group_key_to_notifications.rb new file mode 100644 index 0000000000..2e2a302fff --- /dev/null +++ b/db/migrate/20240513095755_add_group_key_to_notifications.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddGroupKeyToNotifications < ActiveRecord::Migration[7.1] + def change + add_column :notifications, :group_key, :string + end +end diff --git a/db/migrate/20240513123807_add_index_notifications_on_account_id_and_group_key.rb b/db/migrate/20240513123807_add_index_notifications_on_account_id_and_group_key.rb new file mode 100644 index 0000000000..66874418b2 --- /dev/null +++ b/db/migrate/20240513123807_add_index_notifications_on_account_id_and_group_key.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddIndexNotificationsOnAccountIdAndGroupKey < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + add_index :notifications, [:account_id, :group_key], algorithm: :concurrently, where: 'group_key IS NOT NULL' + end +end diff --git a/db/schema.rb b/db/schema.rb index 3a47522d26..73f6b464e4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -724,6 +724,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_22_041528) do t.bigint "from_account_id", null: false t.string "type" t.boolean "filtered", default: false, null: false + t.string "group_key" + t.index ["account_id", "group_key"], name: "index_notifications_on_account_id_and_group_key", where: "(group_key IS NOT NULL)" t.index ["account_id", "id", "type"], name: "index_notifications_on_account_id_and_id_and_type", order: { id: :desc } t.index ["account_id", "id", "type"], name: "index_notifications_on_filtered", order: { id: :desc }, where: "(filtered = false)" t.index ["activity_id", "activity_type"], name: "index_notifications_on_activity_id_and_activity_type" diff --git a/lib/active_record/with_recursive.rb b/lib/active_record/with_recursive.rb new file mode 100644 index 0000000000..4bd3e81eed --- /dev/null +++ b/lib/active_record/with_recursive.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +# Add support for writing recursive CTEs in ActiveRecord + +# Initially from Lorin Thwaits (https://github.com/lorint) as per comment: +# https://github.com/vlado/activerecord-cte/issues/16#issuecomment-1433043310 + +# Modified from the above code to change the signature to +# `with_recursive(hash)` and extending CTE hash values to also includes arrays +# of values that get turned into UNION ALL expressions. + +# This implementation has been merged in Rails: https://github.com/rails/rails/pull/51601 + +module ActiveRecord + module QueryMethodsExtensions + def with_recursive(*args) + @with_is_recursive = true + check_if_method_has_arguments!(__callee__, args) + spawn.with_recursive!(*args) + end + + # Like #with_recursive but modifies the relation in place. + def with_recursive!(*args) # :nodoc: + self.with_values += args + @with_is_recursive = true + self + end + + private + + def build_with(arel) + return if with_values.empty? + + with_statements = with_values.map do |with_value| + raise ArgumentError, "Unsupported argument type: #{with_value} #{with_value.class}" unless with_value.is_a?(Hash) + + build_with_value_from_hash(with_value) + end + + # Was: arel.with(with_statements) + @with_is_recursive ? arel.with(:recursive, with_statements) : arel.with(with_statements) + end + + def build_with_value_from_hash(hash) + hash.map do |name, value| + Arel::Nodes::TableAlias.new(build_with_expression_from_value(value), name) + end + end + + def build_with_expression_from_value(value) + case value + when Arel::Nodes::SqlLiteral then Arel::Nodes::Grouping.new(value) + when ActiveRecord::Relation then value.arel + when Arel::SelectManager then value + when Array then value.map { |e| build_with_expression_from_value(e) }.reduce { |result, value| Arel::Nodes::UnionAll.new(result, value) } + else + raise ArgumentError, "Unsupported argument type: `#{value}` #{value.class}" + end + end + end +end + +ActiveSupport.on_load(:active_record) do + ActiveRecord::QueryMethods.prepend(ActiveRecord::QueryMethodsExtensions) +end diff --git a/lib/arel/union_parenthesizing.rb b/lib/arel/union_parenthesizing.rb new file mode 100644 index 0000000000..852d8e92d8 --- /dev/null +++ b/lib/arel/union_parenthesizing.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Fix an issue with `LIMIT` ocurring on the left side of a `UNION` causing syntax errors. +# See https://github.com/rails/rails/issues/40181 + +# The fix has been merged in ActiveRecord: https://github.com/rails/rails/pull/51549 +# TODO: drop this when available in ActiveRecord + +# rubocop:disable all -- This is a mostly vendored file + +module Arel + module Visitors + class ToSql + private + + def infix_value_with_paren(o, collector, value, suppress_parens = false) + collector << "( " unless suppress_parens + collector = if o.left.class == o.class + infix_value_with_paren(o.left, collector, value, true) + else + select_parentheses o.left, collector, false # Changed from `visit o.left, collector` + end + collector << value + collector = if o.right.class == o.class + infix_value_with_paren(o.right, collector, value, true) + else + select_parentheses o.right, collector, false # Changed from `visit o.right, collector` + end + collector << " )" unless suppress_parens + collector + end + + def select_parentheses(o, collector, always_wrap_selects = true) + if o.is_a?(Nodes::SelectStatement) && (always_wrap_selects || require_parentheses?(o)) + collector << "(" + visit o, collector + collector << ")" + collector + else + visit o, collector + end + end + + def require_parentheses?(o) + !o.orders.empty? || o.limit || o.offset + end + end + end +end + +# rubocop:enable all diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 3c7d51ae1a..d498ee02a5 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -151,6 +151,66 @@ RSpec.describe Notification do end end + describe '.paginate_groups_by_max_id' do + let(:account) { Fabricate(:account) } + + let!(:notifications) do + ['group-1', 'group-1', nil, 'group-2', nil, 'group-1', 'group-2', 'group-1'] + .map { |group_key| Fabricate(:notification, account: account, group_key: group_key) } + end + + context 'without since_id or max_id' do + it 'returns the most recent notifications, only keeping one notification per group' do + expect(described_class.without_suspended.paginate_groups_by_max_id(4).pluck(:id)) + .to eq [notifications[7], notifications[6], notifications[4], notifications[2]].pluck(:id) + end + end + + context 'with since_id' do + it 'returns the most recent notifications, only keeping one notification per group' do + expect(described_class.without_suspended.paginate_groups_by_max_id(4, since_id: notifications[4].id).pluck(:id)) + .to eq [notifications[7], notifications[6]].pluck(:id) + end + end + + context 'with max_id' do + it 'returns the most recent notifications after max_id, only keeping one notification per group' do + expect(described_class.without_suspended.paginate_groups_by_max_id(4, max_id: notifications[7].id).pluck(:id)) + .to eq [notifications[6], notifications[5], notifications[4], notifications[2]].pluck(:id) + end + end + end + + describe '.paginate_groups_by_min_id' do + let(:account) { Fabricate(:account) } + + let!(:notifications) do + ['group-1', 'group-1', nil, 'group-2', nil, 'group-1', 'group-2', 'group-1'] + .map { |group_key| Fabricate(:notification, account: account, group_key: group_key) } + end + + context 'without min_id or max_id' do + it 'returns the oldest notifications, only keeping one notification per group' do + expect(described_class.without_suspended.paginate_groups_by_min_id(4).pluck(:id)) + .to eq [notifications[0], notifications[2], notifications[3], notifications[4]].pluck(:id) + end + end + + context 'with max_id' do + it 'returns the oldest notifications, stopping at max_id, only keeping one notification per group' do + expect(described_class.without_suspended.paginate_groups_by_min_id(4, max_id: notifications[4].id).pluck(:id)) + .to eq [notifications[0], notifications[2], notifications[3]].pluck(:id) + end + end + + context 'with min_id' do + it 'returns the most oldest notifications after min_id, only keeping one notification per group' do + expect(described_class.without_suspended.paginate_groups_by_min_id(4, min_id: notifications[0].id).pluck(:id)) + .to eq [notifications[1], notifications[2], notifications[3], notifications[4]].pluck(:id) + end + end + end + describe '.preload_cache_collection_target_statuses' do subject do described_class.preload_cache_collection_target_statuses(notifications) do |target_statuses| diff --git a/spec/requests/api/v2_alpha/notifications_spec.rb b/spec/requests/api/v2_alpha/notifications_spec.rb new file mode 100644 index 0000000000..9bd1a32e9b --- /dev/null +++ b/spec/requests/api/v2_alpha/notifications_spec.rb @@ -0,0 +1,161 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Notifications' do + let(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:notifications write:notifications' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v2_alpha/notifications', :sidekiq_inline do + subject do + get '/api/v2_alpha/notifications', headers: headers, params: params + end + + let(:bob) { Fabricate(:user) } + let(:tom) { Fabricate(:user) } + let(:params) { {} } + + before do + first_status = PostStatusService.new.call(user.account, text: 'Test') + ReblogService.new.call(bob.account, first_status) + mentioning_status = PostStatusService.new.call(bob.account, text: 'Hello @alice') + mentioning_status.mentions.first + FavouriteService.new.call(bob.account, first_status) + FavouriteService.new.call(tom.account, first_status) + FollowService.new.call(bob.account, user.account) + end + + it_behaves_like 'forbidden for wrong scope', 'write write:notifications' + + context 'with no options' do + it 'returns expected notification types', :aggregate_failures do + subject + + expect(response).to have_http_status(200) + expect(body_json_types).to include('reblog', 'mention', 'favourite', 'follow') + end + end + + context 'with exclude_types param' do + let(:params) { { exclude_types: %w(mention) } } + + it 'returns everything but excluded type', :aggregate_failures do + subject + + expect(response).to have_http_status(200) + expect(body_as_json.size).to_not eq 0 + expect(body_json_types.uniq).to_not include 'mention' + end + end + + context 'with types param' do + let(:params) { { types: %w(mention) } } + + it 'returns only requested type', :aggregate_failures do + subject + + expect(response).to have_http_status(200) + expect(body_json_types.uniq).to eq ['mention'] + end + end + + context 'with limit param' do + let(:params) { { limit: 3 } } + + it 'returns the requested number of notifications paginated', :aggregate_failures do + subject + + notifications = user.account.notifications + + expect(body_as_json.size) + .to eq(params[:limit]) + + expect(response) + .to include_pagination_headers( + prev: api_v2_alpha_notifications_url(limit: params[:limit], min_id: notifications.last.id), + # TODO: one downside of the current approach is that we return the first ID matching the group, + # not the last that has been skipped, so pagination is very likely to give overlap + next: api_v2_alpha_notifications_url(limit: params[:limit], max_id: notifications[1].id) + ) + end + end + + def body_json_types + body_as_json.pluck(:type) + end + end + + describe 'GET /api/v2_alpha/notifications/:id' do + subject do + get "/api/v2_alpha/notifications/#{notification.group_key}", headers: headers + end + + let(:notification) { Fabricate(:notification, account: user.account, group_key: 'foobar') } + + it_behaves_like 'forbidden for wrong scope', 'write write:notifications' + + it 'returns http success' do + subject + + expect(response).to have_http_status(200) + end + + context 'when notification belongs to someone else' do + let(:notification) { Fabricate(:notification, group_key: 'foobar') } + + it 'returns http not found' do + subject + + expect(response).to have_http_status(404) + end + end + end + + describe 'POST /api/v2_alpha/notifications/:id/dismiss' do + subject do + post "/api/v2_alpha/notifications/#{notification.group_key}/dismiss", headers: headers + end + + let!(:notification) { Fabricate(:notification, account: user.account, group_key: 'foobar') } + + it_behaves_like 'forbidden for wrong scope', 'read read:notifications' + + it 'destroys the notification' do + subject + + expect(response).to have_http_status(200) + expect { notification.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + context 'when notification belongs to someone else' do + let(:notification) { Fabricate(:notification) } + + it 'returns http not found' do + subject + + expect(response).to have_http_status(404) + end + end + end + + describe 'POST /api/v2_alpha/notifications/clear' do + subject do + post '/api/v2_alpha/notifications/clear', headers: headers + end + + before do + Fabricate(:notification, account: user.account) + end + + it_behaves_like 'forbidden for wrong scope', 'read read:notifications' + + it 'clears notifications for the account' do + subject + + expect(user.account.reload.notifications).to be_empty + expect(response).to have_http_status(200) + end + end +end From 249cbc449c301aef2a21117138d140efb17b0d96 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 3 Jun 2024 05:15:58 -0400 Subject: [PATCH 292/658] Use existing config access to `local_domain` value (#30509) --- app/views/auth/registrations/edit.html.haml | 2 +- app/views/errors/self_destruct.html.haml | 2 +- spec/requests/well_known/oauth_metadata_spec.rb | 2 +- spec/support/signed_request_helpers.rb | 2 +- spec/system/profile_spec.rb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/auth/registrations/edit.html.haml b/app/views/auth/registrations/edit.html.haml index 48350f478e..07d6c1af51 100644 --- a/app/views/auth/registrations/edit.html.haml +++ b/app/views/auth/registrations/edit.html.haml @@ -3,7 +3,7 @@ - if self_destruct? .flash-message.warning - = t('auth.status.self_destruct', domain: ENV.fetch('LOCAL_DOMAIN')) + = t('auth.status.self_destruct', domain: Rails.configuration.x.local_domain) - else = render partial: 'status', locals: { user: @user, strikes: @strikes } diff --git a/app/views/errors/self_destruct.html.haml b/app/views/errors/self_destruct.html.haml index 09b17a5a94..b9ff48f684 100644 --- a/app/views/errors/self_destruct.html.haml +++ b/app/views/errors/self_destruct.html.haml @@ -3,7 +3,7 @@ .simple_form %h1.title= t('self_destruct.title') - %p.lead= t('self_destruct.lead_html', domain: ENV.fetch('LOCAL_DOMAIN')) + %p.lead= t('self_destruct.lead_html', domain: Rails.configuration.x.local_domain) .form-footer %ul.no-list diff --git a/spec/requests/well_known/oauth_metadata_spec.rb b/spec/requests/well_known/oauth_metadata_spec.rb index deef189ac9..3350d59315 100644 --- a/spec/requests/well_known/oauth_metadata_spec.rb +++ b/spec/requests/well_known/oauth_metadata_spec.rb @@ -6,7 +6,7 @@ describe 'The /.well-known/oauth-authorization-server request' do let(:protocol) { ENV.fetch('LOCAL_HTTPS', true) ? :https : :http } before do - host! ENV.fetch('LOCAL_DOMAIN') + host! Rails.configuration.x.local_domain end it 'returns http success with valid JSON response' do diff --git a/spec/support/signed_request_helpers.rb b/spec/support/signed_request_helpers.rb index eba4095e43..8a52179cae 100644 --- a/spec/support/signed_request_helpers.rb +++ b/spec/support/signed_request_helpers.rb @@ -6,7 +6,7 @@ module SignedRequestHelpers headers ||= {} headers['Date'] = Time.now.utc.httpdate - headers['Host'] = ENV.fetch('LOCAL_DOMAIN') + headers['Host'] = Rails.configuration.x.local_domain signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date') key_id = ActivityPub::TagManager.instance.key_uri_for(sign_with) diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index 421b68a169..2517e823b5 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -7,7 +7,7 @@ describe 'Profile' do subject { page } - let(:local_domain) { ENV['LOCAL_DOMAIN'] } + let(:local_domain) { Rails.configuration.x.local_domain } before do as_a_logged_in_user From 91b6502d827e1eea28e18d30930c2b31be89cdd7 Mon Sep 17 00:00:00 2001 From: Shlee Date: Mon, 3 Jun 2024 19:16:11 +1000 Subject: [PATCH 293/658] Revert "Revert "Change default ruby version to 3.3.2 (#30478)"" (#30516) --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4278242bc9..c90d5dc980 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,22 +7,22 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} -# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.1"] -ARG RUBY_VERSION="3.3.1" +# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"] +ARG RUBY_VERSION="3.3.2" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] ARG NODE_MAJOR_VERSION="20" # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] ARG DEBIAN_VERSION="bookworm" # Node image to use for base image based on combined variables (ex: 20-bookworm-slim) FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node -# Ruby image to use for base image based on combined variables (ex: 3.3.1-slim-bookworm) +# Ruby image to use for base image based on combined variables (ex: 3.3.x-slim-bookworm) FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA # Example: v4.2.0-nightly.2023.11.09+something # Overwrite existence of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"] ARG MASTODON_VERSION_PRERELEASE="" -# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"] +# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="pr-12345"] ARG MASTODON_VERSION_METADATA="" # Allow Ruby on Rails to serve static files From d4e094987e530fb0e0fe35e57b8dd00bb919a770 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 3 Jun 2024 11:16:46 -0400 Subject: [PATCH 294/658] Use bundler version 2.5.11 (#30508) --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c62c57dcc2..8bf6f68add 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1050,7 +1050,7 @@ DEPENDENCIES xorcist (~> 1.1) RUBY VERSION - ruby 3.3.1p55 + ruby 3.3.2p78 BUNDLED WITH - 2.5.9 + 2.5.11 From 9ab7e66caeb68df565b47f024ad69a7d29a49e8c Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Tue, 4 Jun 2024 13:29:08 -0400 Subject: [PATCH 295/658] Cleanup leftover Nanobox references (#30550) --- .nanoignore | 19 ------------------- README.md | 2 +- 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 .nanoignore diff --git a/.nanoignore b/.nanoignore deleted file mode 100644 index 80e9397035..0000000000 --- a/.nanoignore +++ /dev/null @@ -1,19 +0,0 @@ -.DS_Store -.git/ -.gitignore - -.bundle/ -.cache/ -config/deploy/* -coverage -docs/ -.env -log/*.log -neo4j/ -node_modules/ -public/assets/ -public/system/ -spec/ -tmp/ -.vagrant/ -vendor/bundle/ diff --git a/README.md b/README.md index 0353a4c675..b8ee3f5dbb 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre - **Ruby** 3.1+ - **Node.js** 18+ -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. +The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, and **Scalingo**. 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. ## Development From 7d9a8c959692fb7121d154412312a7f8e3005186 Mon Sep 17 00:00:00 2001 From: Michael Stanclift Date: Tue, 4 Jun 2024 12:30:22 -0500 Subject: [PATCH 296/658] Set Devcontainer to Ruby 3.3 Bookworm (#30548) --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b5e72a0973..994a41d050 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # For details, see https://github.com/devcontainers/images/tree/main/src/ruby -FROM mcr.microsoft.com/devcontainers/ruby:1-3.2-bullseye +FROM mcr.microsoft.com/devcontainers/ruby:1-3.3-bookworm # Install Rails # RUN gem install rails webdrivers From e5984c95ebdae71b8323dd0c984cb7096d7f3d75 Mon Sep 17 00:00:00 2001 From: Filippo Giunchedi Date: Tue, 4 Jun 2024 22:28:05 +0200 Subject: [PATCH 297/658] Add libvirt provider parameters to Vagrant (#28102) Co-authored-by: Filippo Giunchedi --- Vagrantfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Vagrantfile b/Vagrantfile index 8a95e91f36..89f5536edc 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -151,6 +151,12 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| vb.customize ["modifyvm", :id, "--nictype2", "virtio"] end + config.vm.provider :libvirt do |libvirt| + libvirt.cpus = 3 + libvirt.memory = 8192 + end + + # This uses the vagrant-hostsupdater plugin, and lets you # access the development site at http://mastodon.local. # If you change it, also change it in .env.vagrant before provisioning From f40f3cb82e2bf18670e25a1d1675a6f8a202257d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:22:02 +0200 Subject: [PATCH 298/658] chore(deps): update dependency rails to v7.1.3.4 (#30551) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 114 +++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8bf6f68add..fadc2bc829 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,35 +10,35 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.3) - actionpack (= 7.1.3.3) - activesupport (= 7.1.3.3) + actioncable (7.1.3.4) + actionpack (= 7.1.3.4) + activesupport (= 7.1.3.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.3) - actionpack (= 7.1.3.3) - activejob (= 7.1.3.3) - activerecord (= 7.1.3.3) - activestorage (= 7.1.3.3) - activesupport (= 7.1.3.3) + actionmailbox (7.1.3.4) + actionpack (= 7.1.3.4) + activejob (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.3.3) - actionpack (= 7.1.3.3) - actionview (= 7.1.3.3) - activejob (= 7.1.3.3) - activesupport (= 7.1.3.3) + actionmailer (7.1.3.4) + actionpack (= 7.1.3.4) + actionview (= 7.1.3.4) + activejob (= 7.1.3.4) + activesupport (= 7.1.3.4) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.3.3) - actionview (= 7.1.3.3) - activesupport (= 7.1.3.3) + actionpack (7.1.3.4) + actionview (= 7.1.3.4) + activesupport (= 7.1.3.4) nokogiri (>= 1.8.5) racc rack (>= 2.2.4) @@ -46,15 +46,15 @@ GEM rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.3) - actionpack (= 7.1.3.3) - activerecord (= 7.1.3.3) - activestorage (= 7.1.3.3) - activesupport (= 7.1.3.3) + actiontext (7.1.3.4) + actionpack (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.3) - activesupport (= 7.1.3.3) + actionview (7.1.3.4) + activesupport (= 7.1.3.4) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) @@ -64,22 +64,22 @@ GEM activemodel (>= 4.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.1.3.3) - activesupport (= 7.1.3.3) + activejob (7.1.3.4) + activesupport (= 7.1.3.4) globalid (>= 0.3.6) - activemodel (7.1.3.3) - activesupport (= 7.1.3.3) - activerecord (7.1.3.3) - activemodel (= 7.1.3.3) - activesupport (= 7.1.3.3) + activemodel (7.1.3.4) + activesupport (= 7.1.3.4) + activerecord (7.1.3.4) + activemodel (= 7.1.3.4) + activesupport (= 7.1.3.4) timeout (>= 0.4.0) - activestorage (7.1.3.3) - actionpack (= 7.1.3.3) - activejob (= 7.1.3.3) - activerecord (= 7.1.3.3) - activesupport (= 7.1.3.3) + activestorage (7.1.3.4) + actionpack (= 7.1.3.4) + activejob (= 7.1.3.4) + activerecord (= 7.1.3.4) + activesupport (= 7.1.3.4) marcel (~> 1.0) - activesupport (7.1.3.3) + activesupport (7.1.3.4) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -424,7 +424,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2024.0507) mini_mime (1.1.5) - mini_portile2 (2.8.6) + mini_portile2 (2.8.7) minitest (5.23.1) msgpack (1.7.2) multi_json (1.15.0) @@ -434,7 +434,7 @@ GEM uri net-http-persistent (4.0.2) connection_pool (~> 2.2) - net-imap (0.4.11) + net-imap (0.4.12) date net-protocol net-ldap (0.19.0) @@ -634,20 +634,20 @@ GEM rackup (1.0.0) rack (< 3) webrick - rails (7.1.3.3) - actioncable (= 7.1.3.3) - actionmailbox (= 7.1.3.3) - actionmailer (= 7.1.3.3) - actionpack (= 7.1.3.3) - actiontext (= 7.1.3.3) - actionview (= 7.1.3.3) - activejob (= 7.1.3.3) - activemodel (= 7.1.3.3) - activerecord (= 7.1.3.3) - activestorage (= 7.1.3.3) - activesupport (= 7.1.3.3) + rails (7.1.3.4) + actioncable (= 7.1.3.4) + actionmailbox (= 7.1.3.4) + actionmailer (= 7.1.3.4) + actionpack (= 7.1.3.4) + actiontext (= 7.1.3.4) + actionview (= 7.1.3.4) + activejob (= 7.1.3.4) + activemodel (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) bundler (>= 1.15.0) - railties (= 7.1.3.3) + railties (= 7.1.3.4) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -662,9 +662,9 @@ GEM rails-i18n (7.0.9) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.1.3.3) - actionpack (= 7.1.3.3) - activesupport (= 7.1.3.3) + railties (7.1.3.4) + actionpack (= 7.1.3.4) + activesupport (= 7.1.3.4) irb rackup (>= 1.0.0) rake (>= 12.2) @@ -686,7 +686,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.9.2) - reline (0.5.7) + reline (0.5.8) io-console (~> 0.5) request_store (1.6.0) rack (>= 1.4) @@ -895,7 +895,7 @@ GEM xorcist (1.1.3) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.14) + zeitwerk (2.6.15) PLATFORMS ruby From 1d3b75d124ddcf7bf1148a2a0cacc0b8f82d6340 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 07:22:58 +0000 Subject: [PATCH 299/658] fix(deps): update dependency pg to v8.12.0 (#30549) 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 162f0cb359..bad4fa01e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12941,8 +12941,8 @@ __metadata: linkType: hard "pg@npm:^8.5.0": - version: 8.11.5 - resolution: "pg@npm:8.11.5" + version: 8.12.0 + resolution: "pg@npm:8.12.0" dependencies: pg-cloudflare: "npm:^1.1.1" pg-connection-string: "npm:^2.6.4" @@ -12958,7 +12958,7 @@ __metadata: peerDependenciesMeta: pg-native: optional: true - checksum: 10c0/20f29a41a99bad5931faf4d4a01e7be7fb27e5b5338fdfb06d2368e295c3d3d4ef49958ad57d2b17bad108e5c84574db6244ed8221e6b77a767f64ef12564119 + checksum: 10c0/973e49b5e7327c42fc62806efa8c824159ab7a0b676cefe6eeb51a59b6e226587911ec27697f36c18d69e58a7f4f0b76d0829364087194d13ed431ab7c9c417a languageName: node linkType: hard From f3893ae65de540fac9a6aed5bd6bc50affaf5d26 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 07:23:19 +0000 Subject: [PATCH 300/658] chore(deps): update dependency rubocop-rspec to v2.30.0 (#30529) 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 fadc2bc829..597005b6b0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -751,7 +751,7 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (2.29.2) + rubocop-rspec (2.30.0) rubocop (~> 1.40) rubocop-capybara (~> 2.17) rubocop-factory_bot (~> 2.22) From e4e3875452c13dd76d9aee5e33e7d1e59629a1ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:52:25 +0200 Subject: [PATCH 301/658] New Crowdin Translations (automated) (#30543) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ia.json | 16 +- app/javascript/mastodon/locales/ko.json | 2 +- app/javascript/mastodon/locales/lt.json | 11 +- config/locales/ca.yml | 2 +- config/locales/doorkeeper.ia.yml | 4 +- config/locales/ia.yml | 876 ++++++++++++------------ config/locales/lt.yml | 5 +- config/locales/simple_form.ia.yml | 52 +- config/locales/simple_form.lv.yml | 1 + 9 files changed, 491 insertions(+), 478 deletions(-) diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 4bcf4c88b5..ce4e89e99a 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -58,7 +58,7 @@ "account.open_original_page": "Aperir le pagina original", "account.posts": "Messages", "account.posts_with_replies": "Messages e responsas", - "account.report": "Signalar @{name}", + "account.report": "Reportar @{name}", "account.requested": "Attendente le approbation. Clicca pro cancellar le requesta de sequer", "account.requested_follow": "{name} ha requestate de sequer te", "account.share": "Compartir profilo de @{name}", @@ -274,7 +274,7 @@ "error.unexpected_crash.next_steps": "Tenta refrescar le pagina. Si isto non remedia le problema, es possibile que tu pote totevia usar Mastodon per medio de un altere navigator o application native.", "error.unexpected_crash.next_steps_addons": "Tenta disactivar istes e refrescar le pagina. Si isto non remedia le problema, es possibile que tu pote totevia usar Mastodon per medio de un altere navigator o application native.", "errors.unexpected_crash.copy_stacktrace": "Copiar le traciamento del pila al area de transferentia", - "errors.unexpected_crash.report_issue": "Signalar un defecto", + "errors.unexpected_crash.report_issue": "Reportar problema", "explore.search_results": "Resultatos de recerca", "explore.suggested_follows": "Personas", "explore.title": "Explorar", @@ -468,7 +468,7 @@ "navigation_bar.search": "Cercar", "navigation_bar.security": "Securitate", "not_signed_in_indicator.not_signed_in": "Es necessari aperir session pro acceder a iste ressource.", - "notification.admin.report": "{name} ha signalate {target}", + "notification.admin.report": "{name} ha reportate {target}", "notification.admin.sign_up": "{name} se ha inscribite", "notification.favourite": "{name} ha marcate tu message como favorite", "notification.follow": "{name} te ha sequite", @@ -499,7 +499,7 @@ "notification_requests.title": "Notificationes filtrate", "notifications.clear": "Rader notificationes", "notifications.clear_confirmation": "Es tu secur que tu vole rader permanentemente tote tu notificationes?", - "notifications.column_settings.admin.report": "Nove signalationes:", + "notifications.column_settings.admin.report": "Nove reportos:", "notifications.column_settings.admin.sign_up": "Nove inscriptiones:", "notifications.column_settings.alert": "Notificationes de scriptorio", "notifications.column_settings.favourite": "Favorites:", @@ -636,7 +636,7 @@ "report.close": "Facite", "report.comment.title": "Ha il altere cosas que nos deberea saper?", "report.forward": "Reinviar a {target}", - "report.forward_hint": "Le conto es de un altere servitor. Inviar un copia anonymisate del signalation a illo tamben?", + "report.forward_hint": "Le conto es de un altere servitor. Inviar un copia anonymisate del reporto a illo tamben?", "report.mute": "Silentiar", "report.mute_explanation": "Tu non videra le messages de iste persona. Ille pote totevia sequer te e vider tu messages e non sapera de esser silentiate.", "report.next": "Sequente", @@ -656,11 +656,11 @@ "report.statuses.subtitle": "Selige tote le responsas appropriate", "report.statuses.title": "Existe alcun messages que appoia iste reporto?", "report.submit": "Submitter", - "report.target": "Signalamento de {target}", + "report.target": "Reportage de {target}", "report.thanks.take_action": "Ecce tu optiones pro controlar lo que tu vide sur Mastodon:", "report.thanks.take_action_actionable": "Durante que nos revide isto, tu pote prender mesuras contra @{name}:", "report.thanks.title": "Non vole vider isto?", - "report.thanks.title_actionable": "Gratias pro signalar, nos investigara isto.", + "report.thanks.title_actionable": "Gratias pro reportar, nos investigara isto.", "report.unfollow": "Cessar de sequer @{name}", "report.unfollow_explanation": "Tu seque iste conto. Pro non plus vider su messages in tu fluxo de initio, cessa de sequer lo.", "report_notification.attached_statuses": "{count, plural, one {{count} message} other {{count} messages}} annexate", @@ -747,7 +747,7 @@ "status.replied_to": "Respondite a {name}", "status.reply": "Responder", "status.replyAll": "Responder al discussion", - "status.report": "Signalar @{name}", + "status.report": "Reportar @{name}", "status.sensitive_warning": "Contento sensibile", "status.share": "Compartir", "status.show_filter_reason": "Monstrar in omne caso", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 7cd74fa501..277a87fe3e 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -414,7 +414,7 @@ "limited_account_hint.action": "그래도 프로필 보기", "limited_account_hint.title": "이 프로필은 {domain}의 중재자에 의해 숨겨진 상태입니다.", "link_preview.author": "{name}", - "link_preview.more_from_author": "{name} 더 둘러보기", + "link_preview.more_from_author": "{name} 프로필 보기", "lists.account.add": "리스트에 추가", "lists.account.remove": "리스트에서 제거", "lists.delete": "리스트 삭제", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 40541b3757..307230036c 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -217,7 +217,7 @@ "domain_block_modal.title": "Blokuoti domeną?", "domain_block_modal.you_will_lose_followers": "Visi tavo sekėjai iš šio serverio bus pašalinti.", "domain_block_modal.you_wont_see_posts": "Nematysi naudotojų įrašų ar pranešimų šiame serveryje.", - "domain_pill.activitypub_lets_connect": "Tai leidžia tau sąveikauti su žmonėmis ne tik Mastodon, bet ir įvairiose socialinėse programėlėse.", + "domain_pill.activitypub_lets_connect": "Tai leidžia tau prisijungti ir bendrauti su žmonėmis ne tik Mastodon, bet ir įvairiose socialinėse programėlėse.", "domain_pill.activitypub_like_language": "ActivityPub – tai tarsi kalba, kuria Mastodon kalba su kitais socialiniais tinklais.", "domain_pill.server": "Serveris", "domain_pill.their_handle": "Jų socialinis medijos vardas:", @@ -433,7 +433,15 @@ "loading_indicator.label": "Kraunama…", "media_gallery.toggle_visible": "{number, plural, one {Slėpti vaizdą} few {Slėpti vaizdus} many {Slėpti vaizdo} other {Slėpti vaizdų}}", "moved_to_account_banner.text": "Tavo paskyra {disabledAccount} šiuo metu išjungta, nes persikėlei į {movedToAccount}.", + "mute_modal.hide_from_notifications": "Slėpti nuo pranešimų", + "mute_modal.hide_options": "Slėpti parinktis", + "mute_modal.indefinite": "Kol atšauksiu jų nutildymą", "mute_modal.show_options": "Rodyti parinktis", + "mute_modal.they_can_mention_and_follow": "Jie gali tave paminėti ir sekti, bet tu jų nematysi.", + "mute_modal.they_wont_know": "Jie nežinos, kad buvo nutildyti.", + "mute_modal.title": "Nutildyti naudotoją?", + "mute_modal.you_wont_see_mentions": "Nematysi įrašus, kuriuose jie paminimi.", + "mute_modal.you_wont_see_posts": "Jie vis tiek gali matyti tavo įrašus, bet tu nematysi jų.", "navigation_bar.about": "Apie", "navigation_bar.advanced_interface": "Atidaryti išplėstinę žiniatinklio sąsają", "navigation_bar.blocks": "Užblokuoti naudotojai", @@ -478,6 +486,7 @@ "notification.own_poll": "Tavo apklausa baigėsi", "notification.poll": "Apklausa, kurioje balsavai, pasibaigė", "notification.reblog": "{name} pakėlė tavo įrašą", + "notification.relationships_severance_event": "Prarasti sąryšiai su {name}", "notification.relationships_severance_event.learn_more": "Sužinoti daugiau", "notification.relationships_severance_event.user_domain_block": "Tu užblokavai {target}. Pašalinama {followersCount} savo sekėjų ir {followingCount, plural, one {# paskyrą} few {# paskyrai} many {# paskyros} other {# paskyrų}}, kurios seki.", "notification.status": "{name} ką tik paskelbė", diff --git a/config/locales/ca.yml b/config/locales/ca.yml index ec32f771e9..c91ae64a7a 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -466,7 +466,7 @@ ca: status: Estat suppress: Suprimeix les recomanacions de seguiment suppressed: Suprimit - title: Seguir les recomanacions + title: Recomanacions de comptes a seguir unsuppress: Restaurar les recomanacions de seguiment instances: availability: diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index 9c493e3d7f..82a1b4b140 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -154,7 +154,7 @@ ia: admin:read:domain_blocks: leger informationes sensibile de tote le blocadas de dominio admin:read:email_domain_blocks: leger informationes sensibile de tote le blocadas de dominio email admin:read:ip_blocks: leger informationes sensibile de tote le blocadas de IP - admin:read:reports: leger information sensibile de tote le reportos e contos signalate + admin:read:reports: leger information sensibile de tote le reportos e contos reportate admin:write: modificar tote le datos in le servitor admin:write:accounts: exequer action de moderation sur contos admin:write:canonical_email_blocks: exequer actiones de moderation sur blocadas de email canonic @@ -192,5 +192,5 @@ ia: write:media: incargar files de medios write:mutes: silentiar personas e conversationes write:notifications: rader tu notificationes - write:reports: signalar altere personas + write:reports: reportar altere personas write:statuses: publicar messages diff --git a/config/locales/ia.yml b/config/locales/ia.yml index ab1f674fd8..cadc465c55 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -59,7 +59,7 @@ ia: destroyed_msg: Le datos de %{username} es ora in cauda pro lor imminente deletion disable: Gelar disable_sign_in_token_auth: Disactivar le authentication per token in e-mail - disable_two_factor_authentication: Disactivar authentication bifactorial + disable_two_factor_authentication: Disactivar A2F disabled: Gelate display_name: Nomine a monstrar domain: Dominio @@ -105,10 +105,10 @@ ia: not_subscribed: Non subscribite pending: Attende revision perform_full_suspension: Suspender - previous_strikes: Previe admonitiones + previous_strikes: Sanctiones precedente previous_strikes_description_html: - one: Iste conto ha un admonition. - other: Iste conto ha %{count} admonitiones. + one: Iste conto ha un sanction. + other: Iste conto ha %{count} sanctiones. promote: Promover protocol: Protocollo public: Public @@ -143,11 +143,11 @@ ia: shared_inbox_url: URL del cassa de entrata condividite show: created_reports: Reportos facite - targeted_reports: Signalate per alteres + targeted_reports: Reportate per alteres silence: Limitar silenced: Limitate statuses: Messages - strikes: Previe admonitiones + strikes: Sanctiones precedente subscribe: Subscriber suspend: Suspender suspended: Suspendite @@ -178,21 +178,21 @@ ia: confirm_user: Confirmar le usator create_account_warning: Crear un advertimento create_announcement: Crear annuncio - create_canonical_email_block: Crear blocada de email - create_custom_emoji: Crear emoticone personalisate + create_canonical_email_block: Crear blocada de e-mail + create_custom_emoji: Crear emoji personalisate create_domain_allow: Crear permisso de dominio create_domain_block: Crear blocada de dominio - create_email_domain_block: Crear blocada de dominio email + create_email_domain_block: Crear blocada de dominio de e-mail create_ip_block: Crear un regula IP create_unavailable_domain: Crear dominio indisponibile create_user_role: Crear un rolo demote_user: Degradar usator destroy_announcement: Deler annuncio - destroy_canonical_email_block: Deler blocada de email - destroy_custom_emoji: Deler emoticone personalisate + destroy_canonical_email_block: Deler blocada de e-mail + destroy_custom_emoji: Deler emoji personalisate destroy_domain_allow: Deler permisso de dominio destroy_domain_block: Deler blocada de dominio - destroy_email_domain_block: Crear blocada de dominio email + destroy_email_domain_block: Crear blocada de dominio de e-mail destroy_instance: Purgar dominio destroy_ip_block: Deler le regula IP destroy_status: Deler message @@ -234,62 +234,62 @@ ia: assigned_to_self_report_html: "%{name} assignava reporto %{target} a se mesme" change_email_user_html: "%{name} cambiava le adresse de e-mail address del usator %{target}" change_role_user_html: "%{name} cambiava rolo de %{target}" - confirm_user_html: "%{name} confirmava le adresse email del usator %{target}" + confirm_user_html: "%{name} confirmava le adresse de e-mail del usator %{target}" create_account_warning_html: "%{name} inviava un advertimento a %{target}" create_announcement_html: "%{name} creava un nove annuncio %{target}" - create_canonical_email_block_html: "%{name} blocava email con le hash %{target}" - create_custom_emoji_html: "%{name} cargava nove emoticone %{target}" + create_canonical_email_block_html: "%{name} blocava e-mail con le hash %{target}" + create_custom_emoji_html: "%{name} incargava le nove emoji %{target}" create_domain_allow_html: "%{name} permitteva federation con dominio %{target}" create_domain_block_html: "%{name} blocava dominio %{target}" - create_email_domain_block_html: "%{name} blocava dominio email %{target}" + create_email_domain_block_html: "%{name} blocava dominio de e-mail %{target}" create_ip_block_html: "%{name} creava regula pro IP %{target}" - create_unavailable_domain_html: "%{name} stoppava consignation a dominio %{target}" + create_unavailable_domain_html: "%{name} stoppava livration al dominio %{target}" create_user_role_html: "%{name} creava rolo de %{target}" demote_user_html: "%{name} degradava usator %{target}" destroy_announcement_html: "%{name} deleva annuncio %{target}" - destroy_canonical_email_block_html: "%{name} disblocava email con le hash %{target}" + destroy_canonical_email_block_html: "%{name} disblocava e-mail con le hash %{target}" destroy_custom_emoji_html: "%{name} deleva emoji %{target}" destroy_domain_allow_html: "%{name} impediva le federation con dominio %{target}" destroy_domain_block_html: "%{name} disblocava dominio %{target}" - destroy_email_domain_block_html: "%{name} disblocava le dominio email %{target}" + destroy_email_domain_block_html: "%{name} disblocava dominio de e-mail %{target}" destroy_instance_html: "%{name} purgava le dominio %{target}" destroy_ip_block_html: "%{name} deleva le regula pro IP %{target}" - destroy_status_html: "%{name} removeva le message de %{target}" - destroy_unavailable_domain_html: "%{name} resumeva le consignation al dominio %{target}" - destroy_user_role_html: "%{name} deleva le rolo de %{target}" + destroy_status_html: "%{name} removeva un message de %{target}" + destroy_unavailable_domain_html: "%{name} reprendeva le livration al dominio %{target}" + destroy_user_role_html: "%{name} deleva le rolo %{target}" disable_2fa_user_html: "%{name} disactivava le authentication a duo factores pro le usator %{target}" - disable_custom_emoji_html: "%{name} disactivava le emoticone %{target}" - disable_sign_in_token_auth_user_html: "%{name} disactivava authentication per testimonio via email pro %{target}" - disable_user_html: "%{name} disactivava le accesso pro le usator %{target}" - enable_custom_emoji_html: "%{name} activava le emoticone %{target}" - enable_sign_in_token_auth_user_html: "%{name} activava le authentication per testimonio via email pro %{target}" - enable_user_html: "%{name} activava le accesso pro le usator %{target}" - memorialize_account_html: "%{name} mutava le conto de %{target} in un pagina commemorative" + disable_custom_emoji_html: "%{name} disactivava le emoji %{target}" + disable_sign_in_token_auth_user_html: "%{name} disactivava le authentication per token de e-mail pro %{target}" + disable_user_html: "%{name} disactivava le apertura de session pro le usator %{target}" + enable_custom_emoji_html: "%{name} activava le emoji %{target}" + enable_sign_in_token_auth_user_html: "%{name} activava le authentication per token de e-mail pro %{target}" + enable_user_html: "%{name} activava le apertura de session pro le usator %{target}" + memorialize_account_html: "%{name} converteva le conto de %{target} in un pagina commemorative" promote_user_html: "%{name} promoveva le usator %{target}" reject_appeal_html: "%{name} refusava le appello del decision de moderation de %{target}" reject_user_html: "%{name} refusava le inscription de %{target}" remove_avatar_user_html: "%{name} removeva le avatar de %{target}" reopen_report_html: "%{name} reaperiva le reporto %{target}" - resend_user_html: "%{name} reinviava le email de confirmation pro %{target}" + resend_user_html: "%{name} reinviava le e-mail de confirmation pro %{target}" reset_password_user_html: "%{name} reinitialisava le contrasigno del usator %{target}" resolve_report_html: "%{name} resolveva le reporto %{target}" - sensitive_account_html: "%{name} marcava como sensibile le medios de %{target}" + sensitive_account_html: "%{name} marcava le multimedia de %{target} como sensibile" silence_account_html: "%{name} limitava le conto de %{target}" suspend_account_html: "%{name} suspendeva le conto de %{target}" - unassigned_report_html: "%{name} de-assignava le reporto %{target}" - unblock_email_account_html: "%{name} disblocava le adresse email de %{target}" - unsensitive_account_html: "%{name} dismarcava como sensibile le medios de %{target}" + unassigned_report_html: "%{name} disassignava le reporto %{target}" + unblock_email_account_html: "%{name} disblocava le adresse de e-mail de %{target}" + unsensitive_account_html: "%{name} dismarcava le multimedia de %{target} como sensibile" unsilence_account_html: "%{name} removeva le limite del conto de %{target}" unsuspend_account_html: "%{name} removeva le suspension del conto de %{target}" update_announcement_html: "%{name} actualisava le annuncio %{target}" - update_custom_emoji_html: "%{name} actualisava le emoticone %{target}" + update_custom_emoji_html: "%{name} actualisava le emoji %{target}" update_domain_block_html: "%{name} actualisava le blocada de dominio pro %{target}" - update_ip_block_html: "%{name} cambiava le regula pro IP %{target}" - update_report_html: "%{name} actualisava le reporto %{target}" - update_status_html: "%{name} actualisava le message per %{target}" - update_user_role_html: "%{name} cambiava le rolo de %{target}" + update_ip_block_html: "%{name} cambiava regula pro IP %{target}" + update_report_html: "%{name} actualisava reporto %{target}" + update_status_html: "%{name} actualisava message de %{target}" + update_user_role_html: "%{name} cambiava rolo de %{target}" deleted_account: conto delite - empty: Nulle registrationes trovate. + empty: Nulle registros trovate. filter_by_action: Filtrar per action filter_by_user: Filtrar per usator title: Registro de inspection @@ -298,7 +298,7 @@ ia: edit: title: Modificar annuncio empty: Necun annuncios trovate. - live: Al vivo + live: In directo new: create: Crear annuncio title: Nove annuncio @@ -316,15 +316,15 @@ ia: by_domain: Dominio copied_msg: Copia local del emoji create con successo copy: Copiar - copy_failed_msg: Impossibile crear un copia local de ille emoticone + copy_failed_msg: Non poteva crear un copia local de ille emoji create_new_category: Crear nove categoria created_msg: Emoji create con successo! delete: Deler - destroyed_msg: Emoticone destruite con successo destroyed! + destroyed_msg: Emoji destruite con successo! disable: Disactivar disabled: Disactivate disabled_msg: Emoji disactivate con successo - emoji: Emoticone + emoji: Emoji enable: Activar enabled: Activate enabled_msg: Emoji activate con successo @@ -333,24 +333,24 @@ ia: listed: Listate new: title: Adder nove emoji personalisate - no_emoji_selected: Nulle emoticones ha essite cambiate perque nulle ha essite seligite + no_emoji_selected: Necun emoji ha essite cambiate perque necun ha essite seligite not_permitted: Tu non es autorisate a exequer iste action overwrite: Superscriber - shortcode: Via breve + shortcode: Codice curte shortcode_hint: Al minus 2 characteres, solo characteres alphanumeric e lineettas basse title: Emojis personalisate uncategorized: Sin categoria unlist: Non listar unlisted: Non listate - update_failed_msg: Impossibile actualisar ille emoticone - updated_msg: Emoticone actualisate con successo! + update_failed_msg: Non poteva actualisar le emoji + updated_msg: Emoji actualisate con successo! upload: Incargar dashboard: active_users: usatores active interactions: interactiones - media_storage: Immagazinage de medios + media_storage: Immagazinage multimedial new_users: nove usatores - opened_reports: reportos aperte + opened_reports: reportos aperite pending_appeals_html: one: "%{count} appello pendente" other: "%{count} appellos pendente" @@ -377,7 +377,7 @@ ia: title: Appellos domain_allows: add_new: Permitter federation con dominio - created_msg: Le dominio ha essite permittite con successo pro federation + created_msg: Le dominio ha essite correctemente autorisate pro federation destroyed_msg: Le dominio ha essite prohibite pro federation export: Exportar import: Importar @@ -390,7 +390,7 @@ ia: permanent_action: Disfacer le suspension non restaurara alcun datos o relation. preamble_html: Tu es sur le puncto de suspender %{domain} e su subdominios. remove_all_data: Isto removera de tu servitor tote le contento, multimedia e datos de profilo del contos de iste dominio. - stop_communication: Tu servitor stoppara le communication con iste servitores. + stop_communication: Tu servitor cessara de communicar con iste servitores. title: Confirmar le blocada del dominio %{domain} undo_relationships: Isto disfacera omne relation de sequimento inter le contos de iste servitores e illos del tue. created_msg: Le blocada del dominio es ora in tractamento @@ -406,7 +406,7 @@ ia: hint: Le blocada del dominio non impedira le creation de entratas de conto in le base de datos, ma applicara retroactive- e automaticamente le methodos specific de moderation a iste contos. severity: desc_html: "Limitar rendera le messages del contos de iste dominio invisibile pro tote persona que non los seque. Suspender removera de tu servitor tote le contento, multimedia e datos de profilo del contos de iste dominio. Usa Necun si tu solmente vole rejectar le files multimedial." - noop: Nemo + noop: Necun silence: Limitar suspend: Suspender title: Nove blocada de dominio @@ -462,11 +462,11 @@ ia: no_file: Necun file seligite follow_recommendations: description_html: "Le recommendationes de sequimento adjuta le nove usatores a trovar rapidemente contento interessante. Quando un usator non ha un historia sufficiente de interactiones con alteres pro formar recommendationes personalisate de sequimento, iste contos es recommendate. Illos se recalcula cata die a partir de un mixtura de contos con le plus grande numero de ingagiamentos recente e le numero de sequitores local le plus alte pro un lingua date." - language: Per lingua + language: Pro le lingua status: Stato suppress: Supprimer recommendation de sequimento suppressed: Supprimite - title: Sequer le recommendationes + title: Recommendationes de contos a sequer unsuppress: Restaurar recommendation de sequimento instances: availability: @@ -504,7 +504,7 @@ ia: instance_follows_measure: lor sequitores hic instance_languages_dimension: Linguas principal instance_media_attachments_measure: annexos multimedial immagazinate - instance_reports_measure: signalationes sur illos + instance_reports_measure: reportos sur illes instance_statuses_measure: messages immagazinate delivery: all: Totes @@ -517,7 +517,7 @@ ia: delivery_error_days: Dies de errores de livration delivery_error_hint: Si le livration non es possibile durante %{count} dies, illo essera automaticamente marcate como non livrabile. destroyed_msg: Le datos de %{domain} es ora in cauda pro deletion imminente. - empty: Necun dominios trovate. + empty: Necun dominio trovate. known_accounts: one: "%{count} conto cognoscite" other: "%{count} contos cognoscite" @@ -533,7 +533,7 @@ ia: total_blocked_by_us: Blocate per nos total_followed_by_them: Sequite per illes total_followed_by_us: Sequite per nos - total_reported: Signalationes sur illes + total_reported: Reportos sur illes total_storage: Annexos multimedial totals_time_period_hint_html: Le totales monstrate hic infra include le datos de tote le tempore. unknown_instance: Iste dominio non es actualmente cognoscite sur iste servitor. @@ -579,24 +579,24 @@ ia: status: Stato title: Repetitores report_notes: - created_msg: Nota de signalation create con successo! - destroyed_msg: Nota de signalation delite con successo! + created_msg: Nota de reporto create con successo! + destroyed_msg: Nota de reporto delite con successo! reports: account: notes: one: "%{count} nota" other: "%{count} notas" action_log: Registro de inspection - action_taken_by: Action prendite per + action_taken_by: Mesura prendite per actions: - delete_description_html: Le messages signalate essera delite e un admonition essera registrate pro adjutar te a prender mesuras in caso de futur infractiones proveniente del mesme conto. - mark_as_sensitive_description_html: Le files multimedial in le messages reportate essera marcate como sensibile e un admonition essera registrate pro adjutar te a prender mesuras in caso de futur infractiones proveniente del mesme conto. + delete_description_html: Le messages reportate essera delite e un sanction essera registrate pro adjutar te a prender mesuras adequate in caso de futur infractiones committite desde le mesme conto. + mark_as_sensitive_description_html: Le files multimedial in le messages reportate essera marcate como sensibile e un sanction essera registrate pro adjutar te a prender mesuras adequate in caso de futur infractiones committite desde le mesme conto. other_description_html: Vider plus optiones pro controlar le comportamento del conto e personalisar le communication al conto signalate. - resolve_description_html: Necun action essera prendite contra le conto signalate, necun admonition registrate, e le signalation essera claudite. - silence_description_html: Iste conto essera visibile solmente a qui ja lo seque o manualmente lo cerca, limitante gravemente su portata. Pote sempre esser revertite. Claude tote le signalationes contra iste conto. - suspend_description_html: Le conto e tote su contento essera inaccessible e finalmente delite, e interager con illo essera impossibile. Reversibile intra 30 dies. Claude tote le signalationes contra iste conto. - actions_description_html: Decide qual action prender pro resolver iste signalation. Si tu prende un action punitive contra le conto signalate, le persona recipera un notification in e-mail, excepte si le categoria Spam es seligite. - actions_description_remote_html: Decide qual action prender pro resolver iste signalation. Isto affectara solmente le maniera in que tu servitor communica con iste conto remote e gere su contento. + resolve_description_html: Necun mesura essera prendite contra le conto denunciate, necun sanction registrate, e le reporto essera claudite. + silence_description_html: Iste conto essera visibile solmente a qui ja lo seque o manualmente lo cerca, limitante gravemente su portata. Pote sempre esser revertite. Claude tote le reportos contra iste conto. + suspend_description_html: Le conto e tote su contento essera inaccessibile e finalmente delite, e interager con illo essera impossibile. Reversibile intra 30 dies. Claude tote le reportos contra iste conto. + actions_description_html: Decide qual mesura prender pro resolver iste reporto. Si tu prende un mesura punitive contra le conto reportate, le persona recipera un notification in e-mail, excepte si le categoria Spam es seligite. + actions_description_remote_html: Decide qual mesura prender pro resolver iste reporto. Isto affectara solmente le maniera in que tu servitor communica con iste conto remote e gere su contento. add_to_report: Adder plus al reporto already_suspended_badges: local: Ja suspendite sur iste servitor @@ -604,19 +604,19 @@ ia: are_you_sure: Es tu secur? assign_to_self: Assignar a me assigned: Moderator assignate - by_target_domain: Dominio del conto signalate + by_target_domain: Dominio del conto reportate cancel: Cancellar category: Categoria - category_description_html: Le motivo pro le qual iste conto e/o contento ha essite signalate essera citate in le communication con le conto signalate + category_description_html: Le motivo pro le qual iste conto e/o contento ha essite reportate essera citate in le communication con le conto reportate comment: none: Necun comment_description_html: 'Pro fornir plus information, %{name} ha scribite:' confirm: Confirmar - confirm_action: Confirmar le action de moderation contra %{acct} - created_at: Signalate + confirm_action: Confirmar le mesura de moderation contra %{acct} + created_at: Reportate delete_and_resolve: Deler le messages forwarded: Reexpedite - forwarded_replies_explanation: Iste signalation proveni de un usator remote e concerne contento remote. Illo te ha essite reexpedite perque le contento signalate es in responsa a un usator tue. + forwarded_replies_explanation: Iste reporto proveni de un usator remote e concerne contento remote. Illo te ha essite reexpedite perque le contento reportate es in responsa a un usator tue. forwarded_to: Reexpedite a %{domain} mark_as_resolved: Marcar como resolvite mark_as_sensitive: Marcar como sensibile @@ -627,41 +627,41 @@ ia: create_and_resolve: Resolver con nota create_and_unresolve: Reaperir con nota delete: Deler - placeholder: Describe le actiones prendite, o insere altere information pertinente... + placeholder: Describe le mesuras prendite, o insere altere information pertinente... title: Notas - notes_description_html: Vider e lassar notas pro altere moderatores e pro tu proprie futuro + notes_description_html: Vider e lassar notas a altere moderatores e a tu ego futur processed_msg: 'Reporto #%{id} elaborate con successo' quick_actions_description_html: 'Face un rapide action o rola a basso pro vider le contento reportate:' remote_user_placeholder: le usator remote ab %{instance} reopen: Reaperir reporto report: 'Reporto #%{id}' - reported_account: Conto signalate - reported_by: Signalate per + reported_account: Conto reportate + reported_by: Reportate per resolved: Resolvite resolved_msg: Reporto resolvite con successo! skip_to_actions: Saltar al actiones status: Stato - statuses: Contento signalate - statuses_description_html: Le contento offensive sera citate in communication con le conto reportate + statuses: Contento reportate + statuses_description_html: Le contento offensive essera citate in communication con le conto reportate summary: action_preambles: - delete_html: 'Tu va remover parte de messages de @%{acct}. Isto ira:' - mark_as_sensitive_html: 'Tu va marcar parte de messages de @%{acct} como sensibile. Isto ira:' - silence_html: 'Tu va limitar le conto de @%{acct}. Isto ira:' - suspend_html: 'Tu va limitar le conto de @%{acct}. Isto ira:' + delete_html: 'Tu es sur le puncto de remover alcunes del messages de @%{acct}. Isto va:' + mark_as_sensitive_html: 'Tu es sur le puncto de marcar alcunes del messages de @%{acct} como sensibile. Isto va:' + silence_html: 'Tu es sur le puncto de limitar le conto de @%{acct}. Isto va:' + suspend_html: 'Tu es sur le puncto de suspender le conto de @%{acct}. Isto va:' actions: delete_html: Remover le messages offensive - mark_as_sensitive_html: Marcar le medios de messages offensive como sensibile + mark_as_sensitive_html: Marcar le multimedia de messages offensive como sensibile silence_html: Limitar gravemente le portata de @%{acct} rendente le profilo e contento visibile solmente a qui ja lo seque o lo cerca manualmente suspend_html: Suspender @%{acct}, rendente le profilo e contento inaccessibile e le interaction con illo impossibile - close_report: Marcar le signalation №%{id} como resolvite - close_reports_html: Marcar tote le signalationes contra @%{acct} como resolvite + close_report: 'Marcar le reporto #%{id} como resolvite' + close_reports_html: Marcar tote le reportos contra @%{acct} como resolvite delete_data_html: Deler le profilo e contento de @%{acct} in 30 dies excepte si le suspension es disfacite intertanto preview_preamble_html: "@%{acct} recipera un advertimento con le sequente contento:" - record_strike_html: Registrar un admonition contra @%{acct} pro adjutar te a imponer sanctiones in caso de futur violationes de iste conto + record_strike_html: Registra un sanction contra @%{acct} pro adjutar te a prender mesuras adequate in caso de futur violationes committite desde iste conto send_email_html: Inviar un e-mail de advertimento a @%{acct} warning_placeholder: Motivation supplementari facultative pro le action de moderation. - target_origin: Origine del conto signalate + target_origin: Origine del conto reportate title: Reportos unassign: Disassignar unknown_action_msg: 'Action incognite: %{action}' @@ -707,7 +707,7 @@ ia: manage_invites: Gerer le invitationes manage_invites_description: Permitte que usatores examina e deactiva ligamines de invitation manage_reports: Gerer le reportos - manage_reports_description: Permitte que usatores revide signalationes e exeque actiones de moderation a base de illos + manage_reports_description: Permitte que usatores revide reportos e prende mesuras de moderation a base de illos manage_roles: Gerer le rolos manage_roles_description: Permitte que usatores gere e assigna rolos inferior a lor privilegios actual manage_rules: Gerer le regulas @@ -716,7 +716,7 @@ ia: manage_settings_description: Permitte que usatores cambia le parametros del sito manage_taxonomies: Gerer taxonomias manage_taxonomies_description: Permitte que usatores revide contento in tendentias e actualisa le parametros de hashtag - manage_user_access: Gerer le accessos de usator + manage_user_access: Gerer le accesso de usatores manage_user_access_description: Permitte que usatores disactiva le authentication bifactorial de altere usatores, cambia lor adresses de e-mail, e reinitialisa lor contrasigno manage_users: Gerer usatores manage_users_description: Permitte que usatores vide le detalios de altere usatores e exeque actiones de moderation contra illes @@ -741,7 +741,7 @@ ia: manage_rules: Gerer le regulas del servitor preamble: Fornir information detaliate sur le functionamento, moderation e financiamento del servitor. rules_hint: Il ha un area dedicate al regulas que tu usatores debe acceptar. - title: A proposito de + title: A proposito appearance: preamble: Personalisar le interfacie web de Mastodon. title: Apparentia @@ -756,43 +756,43 @@ ia: preamble: Controlar como contento generate per le usator es immagazinate in Mastodon. title: Retention de contento default_noindex: - desc_html: Affice tote le usatores qui non ha cambiate iste parametro per se mesme - title: Refusar de ordinario le indexation del usatores per le motores de recerca + desc_html: Affecta tote le usatores qui non ha personalmente cambiate iste parametro + title: Excluder le usatores del indexation del motores de recerca per predefinition discovery: - follow_recommendations: Sequer le recommendationes - preamble: Presentar contento interessante es instrumental in introducer nove usatores qui pote non cognoscer alcuno de Mastodon. + follow_recommendations: Recommendationes de contos a sequer + preamble: Presentar contento interessante es essential pro attraher e retener nove usatores qui pote non cognoscer alcun persona sur Mastodon. Controla como varie optiones de discoperta functiona sur tu servitor. profile_directory: Directorio de profilos public_timelines: Chronologias public publish_discovered_servers: Publicar servitores discoperite - publish_statistics: Publicar statistica - title: Discoperi + publish_statistics: Publicar statisticas + title: Discoperta trends: Tendentias domain_blocks: all: A omnes disabled: A necuno users: A usators local in session registrations: - moderation_recommandation: Per favor verifica que tu ha un adequate e reactive equipa de moderation ante que tu aperi registrationes a quicunque! + moderation_recommandation: Per favor assecura te de haber un equipa de moderation adequate e reactive ante de aperir le inscription a omnes! preamble: Controla qui pote crear un conto sur tu servitor. - title: Registrationes + title: Inscriptiones registrations_mode: modes: approved: Approbation necessari pro le inscription none: Nemo pote inscriber se open: Quicunque pote inscriber se - warning_hint: Nos consilia usar “Approbation necessari pro le inscription” si tu non crede que tu equipa de moderation pote tractar spam e registrationes maligne in un modo opportun. + warning_hint: Nos recommenda usar “Approbation necessari pro le inscription” si tu non es secur que tu equipa de moderation pote tractar spam e inscriptiones malevolente in tempore utile. security: authorized_fetch: Require authentication ab servitores federate authorized_fetch_hint: Requirer authentication de servitores federate permitte un application plus stricte de blocadas a nivello de usator e de servitor. Nonobstante, isto diminue le prestationes del servitor, reduce le portata de tu responsas e pote introducer problemas de compatibilitate con certe servicios federate. In plus, isto non impedira le actores dedicate a recuperar tu messages public e tu contos. - authorized_fetch_overridden_hint: Tu actualmente non pote cambiar iste parametros perque il es superate per un variabile de ambiente. + authorized_fetch_overridden_hint: Tu actualmente non pote cambiar iste parametro perque illo es supplantate per un variabile de ambiente. federation_authentication: Application del authentication de federation title: Parametros de servitor site_uploads: delete: Deler file incargate - destroyed_msg: Incarga de sito delite con successo! + destroyed_msg: Le file incargate al sito ha essite delite! software_updates: - critical_update: Critic! Actualisa tosto - description: Il es recommendate de mantener actualisate tu installation de Mastodon pro beneficiar del ultime reparationes e functiones. In ultra, il es aliquando critic actualisar Mastodon in maniera opportun pro evitar problemas de securitate. Pro iste rationes, Mastodon controla pro actualisationes cata 30 minutas, e te notificara secundo tu preferentias de notificationes per email. + critical_update: Critic – per favor, actualisa rapidemente + description: Il es recommendate mantener tu installation de Mastodon actualisate pro beneficiar del ultime reparationes e functiones. In ultra, de tempore a tempore, il es de importantia critic actualisar Mastodon in tempore utile pro evitar problemas de securitate. Pro iste rationes, Mastodon verifica le presentia de actualisationes cata 30 minutas, e te notificara secundo tu preferentias de notification in e-mail. documentation_link: Pro saper plus release_notes: Notas de version title: Actualisationes disponibile @@ -800,33 +800,33 @@ ia: types: major: Version major minor: Version minor - patch: 'Version de pecias: remedios de bugs e cambiamentos facile a applicar' + patch: 'Version corrective: remedios de bugs e cambiamentos facile a applicar' version: Version statuses: account: Autor application: Application - back_to_account: Retro al pagina de conto + back_to_account: Retornar al pagina del conto back_to_report: Retro al pagina de reporto batch: - remove_from_report: Remover ab reporto + remove_from_report: Remover del reporto report: Reporto deleted: Delite - favourites: Favoritos - history: Chronologia del versiones - in_reply_to: Replicante a + favourites: Favorites + history: Historia de versiones + in_reply_to: In responsa a language: Lingua media: - title: Medios + title: Multimedia metadata: Metadatos - no_status_selected: Nulle messages era cambiate perque necun era seligite + no_status_selected: Necun message ha essite cambiate perque necun ha essite seligite open: Aperir message original_status: Message original - reblogs: Promotiones - status_changed: Messages cambiate + reblogs: Republicationes + status_changed: Message cambiate title: Messages del conto trending: Tendentias visibility: Visibilitate - with_media: Con medios + with_media: Con multimedia strikes: actions: delete_statuses: "%{name} ha delite le messages de %{target}" @@ -853,31 +853,31 @@ ia: message_html: Tu aggregation Elasticsearch ha plus que un nodo, ma Mastodon non es configurate a usar los. elasticsearch_preset_single_node: action: Vide documentation - message_html: Tu aggregation Elasticsearch ha un sol nodo, ES_PRESET deberea esser predefinite a single_node_cluster. + message_html: Tu aggregation Elasticsearch ha un sol nodo, ES_PRESET deberea esser mittite a single_node_cluster. elasticsearch_reset_chewy: - message_html: Le indexation de tu systema Elasticsearch es obsolete per un cambio de configuration. Per cfavor exeque tootctl search deploy --reset-chewy pro actualisar lo. + message_html: Le indexation de tu systema Elasticsearch es obsolete a causa de un cambio de parametro. Per favor exeque tootctl search deploy --reset-chewy pro actualisar lo. elasticsearch_running_check: - message_html: Impossibile connecter se a Elasticsearch. Verifica que illo flue, o disactiva le recerca a plen texto + message_html: Impossibile connecter se a Elasticsearch. Verifica que illo es active, o disactiva le recerca a plen texto elasticsearch_version_check: message_html: 'Version de Elasticsearch incompatibile: %{value}' - version_comparison: Elasticsearch %{running_version} es currente dum %{required_version} es necesse + version_comparison: Elasticsearch %{running_version} es active, ma %{required_version} es requirite rules_check: action: Gerer le regulas del servitor - message_html: Tu non ha definite ulle regulas de servitor. + message_html: Tu non ha definite alcun regula de servitor. sidekiq_process_check: - message_html: Nulle processo Sidekiq currente pro le %{value} cauda(s). Controla tu configuration de Sidekiq + message_html: Necun processo Sidekiq es active pro le cauda(s) %{value}. Per favor verifica tu configuration de Sidekiq software_version_critical_check: action: Vider le actualisationes disponibile - message_html: Un actualisation critic de Mastodon es disponibile, actualisa lo le plus rapide possibile. + message_html: Un actualisation critic de Mastodon es disponibile. Per favor actualisa lo le plus tosto possibile. software_version_patch_check: action: Vider le actualisationes disponibile message_html: Un actualisation de remedio de bug pro Mastodon es disponibile. upload_check_privacy_error: - action: Verifica hic pro plus de information - message_html: "Tu servitor de web es mal-configurate. Le confidentialitate de tu usatores es a risco." + action: Consulta hic pro plus information + message_html: "Tu servitor web es mal configurate. Le confidentialitate de tu usatores es in risco." upload_check_privacy_error_object_storage: - action: Verifica hic pro plus de information - message_html: "Tu immagazinage de objectos es mal-configurate. Le confidentialitate de tu usatores es a risco." + action: Consulta hic pro plus information + message_html: "Tu immagazinage de objectos es mal configurate. Le confidentialitate de tu usatores es in risco." tags: review: Revide le stato updated_msg: Parametros de hashtag actualisate con successo @@ -885,67 +885,67 @@ ia: trends: allow: Permitter approved: Approbate - disallow: Impedir + disallow: Refusar links: allow: Permitter ligamine - allow_provider: Permitter editor - description_html: Istos es ligamines que es actualmente multo compartite per contos de que tu servitor vide messages. Illo pote adjutar tu usatores a discoperir lo que eveni in le mundo. Nulle ligamines es monstrate publicamente usque tu non approba le editor. Tu alsi pote permitter o rejectar ligamines singule. - disallow: Impedir ligamine - disallow_provider: Impedir editor - no_link_selected: Nulle ligamine era cambiate perque nulle era seligite + allow_provider: Autorisar le publicator + description_html: Istes es ligamines que es actualmente compartite multo per contos del quales tu servitor recipe messages. Illos pote adjutar tu usatores a discoperir lo que eveni in le mundo. Necun ligamine es monstrate publicamente usque tu autorisa le publicator. Tu pote tamben permitter o rejectar ligamines singule. + disallow: Prohibir le ligamine + disallow_provider: Prohibir le publicator + no_link_selected: Necun ligamine ha essite cambiate perque necun ha essite seligite publishers: - no_publisher_selected: Nulle editores era cambiate perque nemo era seligite + no_publisher_selected: Necun publicator ha essite cambiate perque necun ha essite seligite shared_by_over_week: one: Compartite per un persona le septimana passate other: Compartite per %{count} personas le septimana passate - title: Ligamines de tendentia - usage_comparison: Compartite %{today} vices hodie, comparate al %{yesterday} de heri - not_allowed_to_trend: Non permittite haber tendentia - only_allowed: Solo permittite + title: Ligamines in tendentia + usage_comparison: Compartite %{today} vices hodie, in comparation con le %{yesterday} de heri + not_allowed_to_trend: Non autorisate a apparer in tendentias + only_allowed: Solo permittites pending_review: Attende revision preview_card_providers: - allowed: Ligamines ab iste editor pote haber tendentia - description_html: Il ha dominios ab que ligamines es sovente compartite sur tu servitor. Ligamines non habera publicamente tendentia salvo que le dominio del ligamine es approbate. Tu approbation (o rejection) se extende al sub-dominios. - rejected: Ligamines ab iste editor non habera tendentia - title: Editores + allowed: Ligamines de iste publicator pote apparer in tendentias + description_html: Istes es le dominios del quales le ligamines es frequentemente compartite sur tu servitor. Le ligamines solmente apparera in le tendentias public si le dominio del ligamine es approbate. Tu approbation (o rejection) se extende al subdominios. + rejected: Ligamines de iste publicator non apparera in tendentias + title: Publicatores rejected: Rejectate statuses: allow: Permitter message allow_account: Permitter autor - description_html: Istos es messages que tu servitor cognosce perque illos es al momento multo compartite e favorite. Isto pote adjutar tu nove e renovate usatores a trovar altere personas a sequer. Nulle messages es monstrate publicamente usque tu approba le autor, e le autor permitte que su conto es suggerite a alteres. Tu alsi pote permitter o rejectar messages singule. - disallow: Impedir message - disallow_account: Impedir autor - no_status_selected: Nulle messages era cambiate perque nulle era seligite - not_discoverable: Le autor non ha optate pro esser detectabile + description_html: Istes es le messages cognoscite sur tu servitor que al momento es multo compartite e marcate como favorite. Illos pote adjutar tu usatores nove e reveniente a trovar plus personas a sequer. Necun message es monstrate publicamente usque tu approba le autor, a condition que le autor permitte que su conto es suggerite a alteres. Tu pote tamben permitter o rejectar messages singule. + disallow: Non permitter message + disallow_account: Non permitter autor + no_status_selected: Necun message in tendentia ha essite cambiate perque necun ha essite seligite + not_discoverable: Le autor non ha optate pro esser discoperibile shared_by: - one: Compartite e favorite un tempore - other: Compartite e favorite %{friendly_count} tempores - title: Messages de tendentia + one: Compartite o marcate como favorite un vice + other: Compartite o marcate como favorite %{friendly_count} vices + title: Messages in tendentia tags: - current_score: Punctuage actual %{score} + current_score: Score actual %{score} dashboard: tag_accounts_measure: usos unic tag_languages_dimension: Linguas principal tag_servers_dimension: Servitores principal tag_servers_measure: servitores differente tag_uses_measure: usos total - description_html: Istos es hashtags que actualmente appare in tante messages que tu servitor vide. Illo pote adjutar tu usatores a discoperir re que le personas parla plus al momento. Nulle hashtags es monstrate publicamente usque tu los approba. + description_html: Istes es hashtags que actualmente appare in multe messages que tu servitor vide. Illos pote adjutar tu usatores a discoperir le cosas sur le quales le gente parla le plus al momento. Nulle hashtags es monstrate publicamente usque tu los approba. listable: Pote esser suggerite - no_tag_selected: Nulle placas era cambiate perque nulle era seligite - not_listable: Non sera suggerite + no_tag_selected: Necun etiquetta ha essite cambiate perque necun ha essite seligite + not_listable: Non essera suggerite not_trendable: Non apparera sub tendentias not_usable: Non pote esser usate - peaked_on_and_decaying: Habeva un picco %{date}, ora decade - title: Hashtags de tendentia + peaked_on_and_decaying: Ha attingite su maximo le %{date}, ora in declino + title: Hashtags in tendentia trendable: Pote apparer sub tendentias - trending_rank: 'De tendentia #%{rank}' + trending_rank: 'Tendentia #%{rank}' usable: Pote esser usate - usage_comparison: Usate %{today} vices hodie, al contrario del %{yesterday} de heri + usage_comparison: Usate %{today} vices hodie, in comparation con le %{yesterday} de heri used_by_over_week: - one: Usate per un persona le ultime septimana - other: Usate per %{count} personas le ultime septimana + one: Usate per un persona in le ultime septimana + other: Usate per %{count} personas in le ultime septimana title: Tendentias - trending: Tendentias + trending: In tendentia warning_presets: add_new: Adder nove delete: Deler @@ -953,46 +953,46 @@ ia: empty: Tu non ha ancora definite alcun avisos predefinite. title: Predefinitiones de avisos webhooks: - add_new: Adder terminal + add_new: Adder puncto final delete: Deler - description_html: Un croc web habilita Mastodon a transmitter notificationes in tempore real re eventos seligite pro tu pro activar application, assi tu application pote automaticamente discatenar reactiones. + description_html: Un webhook o puncto de ancorage web permitte a Mastodon transmitter notificationes in tempore real sur eventos seligite a tu proprie application, de maniera que tu application pote automaticamente activar reactiones. disable: Disactivar disabled: Disactivate - edit: Rediger terminal - empty: Tu ancora non ha configurate alcun punctos final de web croc. + edit: Rediger puncto final + empty: Tu ancora non ha configurate alcun punctos final de webhook. enable: Activar enabled: Active enabled_events: one: 1 evento activate other: "%{count} eventos activate" events: Eventos - new: Nove croc web - rotate_secret: Rotar secrete - secret: Firmante secrete + new: Nove webhook + rotate_secret: Rotar le secreto + secret: Secreto de signatura status: Stato - title: Crocs web - webhook: Crocs web + title: Webhooks + webhook: Webhook admin_mailer: auto_close_registrations: - body: Per un carentia recente de activate de moderator, le registrationes sur %{instance} ha essite automaticamente mutate a besoniante revision manual, pro impedir %{instance} de esser usate como un platteforma pro potential mal actores. Tu pote mutar lo retro pro sempre aperir le registrationes. - subject: Le registrationes pro %{instance} ha essite automaticamente mutate a besoniante de approbation + body: A causa de un manco de activate recente de moderatores, le parametros de inscription sur %{instance} ha essite automaticamente cambiate pro exiger un verification manual, a fin de impedir le possibile uso de %{instance} per actores malevolente. Tu pote reaperir le inscription a omne momento. + subject: Le inscriptiones a %{instance} ha essite automaticamente cambiate pro exiger approbation new_appeal: actions: - delete_statuses: pro deler lor messages - disable: pro gelar lor conto - mark_statuses_as_sensitive: pro marcar lor messages como sensibile - none: pro advertir - sensitive: a marcar lor conto como sensibile - silence: pro limitar lor conto - suspend: pro suspender lor conto - body: "%{target} appella un decision de moderation per %{action_taken_by} ab le %{date}, que era %{type}. Ille scribeva:" - next_steps: Tu pote approbar le appello a disfacer le decision de moderation, o ignorar lo. - subject: "%{username} appella un decision de moderation sur %{instance}" + delete_statuses: deler su messages + disable: gelar su conto + mark_statuses_as_sensitive: marcar su messages como sensibile + none: emitter un advertimento + sensitive: marcar su conto como sensibile + silence: limitar su conto + suspend: suspender su conto + body: "%{target} appella contra un decision de moderation, prendite per %{action_taken_by} le %{date}, de %{type}. Le appellante ha scribite:" + next_steps: Tu pote approbar le appello pro disfacer le decision de moderation, o ignorar lo. + subject: "%{username} appella contra un decision de moderation sur %{instance}" new_critical_software_updates: - body: Nove versiones critic de Mastodon ha essite publicate, tu poterea voler actualisar al plus tosto possibile! + body: Nove versiones critic de Mastodon ha essite publicate, per favor considera actualisar le plus tosto possibile! subject: Actualisationes critic de Mastodon es disponibile pro %{instance}! new_pending_account: - body: Le detalios del nove conto es infra. + body: Le detalios del nove conto es infra. Tu pote approbar o refusar iste demanda. subject: Nove conto preste a revider sur %{instance} (%{username}) new_report: body: "%{reporter} ha reportate %{target}" @@ -1002,30 +1002,30 @@ ia: body: Nove versiones de Mastodon ha essite publicate, tu poterea voler actualisar! subject: Nove versiones de Mastodon es disponibile pro %{instance}! new_trends: - body: 'Le sequente elementos besoniar de un recension ante que illos pote esser monstrate publicamente:' + body: 'Le sequente entratas require un revision ante que illos pote esser monstrate publicamente:' new_trending_links: - title: Ligamines de tendentia + title: Ligamines in tendentia new_trending_statuses: - title: Messages de tendentia + title: Messages in tendentia new_trending_tags: - title: Hashtags de tendentia - subject: Nove tendentias pro recenser sur %{instance} + title: Hashtags in tendentia + subject: Nove tendentias a revider sur %{instance} aliases: add_new: Crear alias - created_msg: Create con successo un nove alias. Ora tu pote initiar le motion ab le vetere conto. - deleted_msg: Removite con successo le alias. Mover de ille conto a isto non sera plus possibile. + created_msg: Le nove alias ha essite create. Ora tu pote initiar le migration desde le conto ancian. + deleted_msg: Le alias ha essite removite. Non essera plus possibile migrar de ille conto a iste. empty: Tu non ha aliases. - hint_html: Si tu desira mover ab un altere conto a isto, ci tu pote crear un alias, que es requirite ante que tu pote continuar con mover sequaces ab le vetere conto a isto. Iste action per se mesme es innocue e reversibile. Le migration de conto es initiate ab le vetere conto. + hint_html: Si tu vole migrar de un altere conto a iste, tu pote crear un alias ci, que es necessari pro poter transferer le sequitores del conto ancian a iste. Iste action per se es innocue e reversibile. Le migration del conto es initiate desde le conto ancian. remove: Disligar alias appearance: advanced_web_interface: Interfacie web avantiate - advanced_web_interface_hint: 'Si tu desira facer uso de tu integre largessa de schermo, le interfacie web avantiate te permitte de configurar plure columnas differente pro vider al mesme tempore tante informationes como tu vole: pagina principal, notificationes, chronogramma federate, ulle numero de listas e hashtags.' + advanced_web_interface_hint: 'Si tu vole utilisar tote le largessa de tu schermo, le interfacie web avantiate te permitte configurar multe columnas differente pro vider al mesme tempore tante informationes como tu vole: pagina principal, notificationes, chronologia federate, un numero illimitate de listas e hashtags.' animations_and_accessibility: Animationes e accessibilitate confirmation_dialogs: Dialogos de confirmation discovery: Discoperta localization: body: Mastodon es traducite per voluntarios. - guide_link: https://crowdin.com/project/mastodon + guide_link: https://crowdin.com/project/mastodon/ia guide_link_text: Totes pote contribuer. sensitive_content: Contento sensibile application_mailer: @@ -1033,110 +1033,110 @@ ia: salutation: "%{name}," settings: 'Cambiar preferentias de e-mail: %{link}' unsubscribe: Desubscriber - view: 'Vider:' + view: 'Visita:' view_profile: Vider profilo view_status: Vider message applications: created: Application create con successo destroyed: Application delite con successo - logout: Clauder le session - regenerate_token: Regenerar testimonio de accesso - token_regenerated: Testimonio de accesso regenerate con successo - warning: Sia multo attente con iste datos. Jammais compartir los con quicunque! - your_token: Tu testimonio de accesso + logout: Clauder session + regenerate_token: Regenerar token de accesso + token_regenerated: Le token de accesso ha essite regenerate + warning: Sia multo prudente con iste datos. Non comparti los jammais con alcuno! + your_token: Tu token de accesso auth: - apply_for_account: Peter un conto + apply_for_account: Requestar un conto captcha_confirmation: help_html: Si tu ha problemas a solver le CAPTCHA, tu pote contactar nos per %{email} e nos pote assister te. - hint_html: Justo un altere cosa! Nos debe confirmar que tu es un human (isto es assi proque nos pote mantener foras le spam!). Solve le CAPTCHA infra e clicca "Continuar". + hint_html: Solo un altere cosa! Nos debe confirmar que tu es un humano (de sorta que nos pote mantener le spam foras!). Solve le CAPTCHA infra e clicca sur "Continuar". title: Controlo de securitate confirmations: - awaiting_review: Tu adresse email es confirmate! Le personal de %{domain} ora revide tu registration. Tu recipera un email si illes approba tu conto! - awaiting_review_title: Tu registration es revidite - clicking_this_link: cliccante iste ligamine - login_link: acceder - proceed_to_login_html: Ora tu pote continuar a %{login_link}. - redirect_to_app_html: Tu deberea haber essite re-dirigite al app %{app_name}. Si isto non eveni, tenta %{clicking_this_link} o manualmente retorna al app. - registration_complete: Tu registration sur %{domain} es ora complete! + awaiting_review: Tu adresse de e-mail es confirmate! Le personal de %{domain} ora revide tu registration. Tu recipera un e-mail si illes approba tu conto! + awaiting_review_title: Tu inscription es in curso de revision + clicking_this_link: cliccar sur iste ligamine + login_link: aperir session + proceed_to_login_html: Ora tu pote %{login_link}. + redirect_to_app_html: Tu deberea haber essite redirigite al app %{app_name}. Si isto non ha evenite, tenta %{clicking_this_link} o retornar manualmente al app. + registration_complete: Tu inscription sur %{domain} es ora concludite! welcome_title: Benvenite, %{name}! - wrong_email_hint: Si ille adresse email non es correcte, tu pote cambiar lo in parametros de conto. + wrong_email_hint: Si ille adresse de e-mail non es correcte, tu pote cambiar lo in le parametros del conto. delete_account: Deler le conto - delete_account_html: Si tu vole a dele tu conto, tu pote continuar ci. Te sera demandate confirmation. + delete_account_html: Si tu vole deler tu conto, tu pote facer lo hic. Te essera demandate un confirmation. description: prefix_invited_by_user: "@%{name} te invita a junger te a iste servitor de Mastodon!" prefix_sign_up: Inscribe te sur Mastodon hodie! - suffix: Con un conto, tu potera sequer personas, messages de actualisation e excambios de messages con usatores de ulle servitor de Mastodon e plus! + suffix: Con un conto, tu potera sequer personas, publicar tu pensatas e excambiar messages con usatores de qualcunque servitor de Mastodon e multo plus! didnt_get_confirmation: Non recipeva tu un ligamine de confirmation? dont_have_your_security_key: Non ha tu le clave de securitate? forgot_password: Contrasigno oblidate? - invalid_reset_password_token: Pete un nove. - link_to_otp: Insere un codice a duo factores o un codice de recuperation ab tu telephono + invalid_reset_password_token: Le token pro reinitialisar le contrasigno non es valide o ha expirate. Per favor requesta un nove. + link_to_otp: Insere un codice a duo factores de tu telephono o un codice de recuperation link_to_webauth: Usa tu apparato clave de securitate - log_in_with: Accede con - login: Accede - logout: Clauder le session - migrate_account: Move a un conto differente - migrate_account_html: Si tu vole re-adressar iste conto a un altere, tu pote configurar lo ci. - or_log_in_with: O accede con - privacy_policy_agreement_html: Io ha legite e acceptar le politica de confidentialitate + log_in_with: Aperir session con + login: Aperir session + logout: Clauder session + migrate_account: Migrar a un altere conto + migrate_account_html: Si tu vole rediriger iste conto a un altere, tu pote configurar lo hic. + or_log_in_with: O aperi session con + privacy_policy_agreement_html: Io ha legite e accepta le politica de confidentialitate progress: - confirm: Confirma le email + confirm: Confirmar e-mail details: Tu detalios review: Nostre revision rules: Accepta le regulas providers: cas: CAS saml: SAML - register: Inscribe te + register: Inscriber se registration_closed: "%{instance} non accepta nove membros" resend_confirmation: Reinviar ligamine de confirmation - reset_password: Remontar le contrasigno + reset_password: Reinitialisar contrasigno rules: accept: Acceptar back: Retro invited_by: 'Tu pote junger te a %{domain} gratias al invitation que tu ha recipite de:' - preamble: Illos es predefinite e fortiarte per le moderatores de %{domain}. - preamble_invited: Ante que tu continua, considera le regulas base definite per le moderatores de %{domain}. - title: Alcun regulas base. + preamble: Istes es definite e applicate per le moderatores de %{domain}. + preamble_invited: Ante que tu continua, considera le regulas de base definite per le moderatores de %{domain}. + title: Alcun regulas de base. title_invited: Tu ha essite invitate. security: Securitate set_new_password: Definir un nove contrasigno setup: - email_below_hint_html: Verifica tu plica de spam, o pete un altero. Tu pote corriger tu adresse email si illo es errate. - email_settings_hint_html: Clicca le ligamine que nos te inviava pro verificar %{email}. - link_not_received: Non obteneva tu un ligamine? - new_confirmation_instructions_sent: Tu recipera un nove email con le ligamine de confirmation in alcun minutas! - title: Verifica tu cassa de ingresso + email_below_hint_html: Consulta tu dossier de spam, o requesta un altere. Tu pote corriger tu adresse de e-mail si illo es errate. + email_settings_hint_html: Clicca sur le ligamine que nos te ha inviate pro verificar %{email}. Nos te attendera hic. + link_not_received: Necun ligamine recipite? + new_confirmation_instructions_sent: Tu recipera un nove e-mail con le ligamine de confirmation in poc minutas! + title: Consulta tu cassa de entrata sign_in: - preamble_html: Accede con tu %{domain} credentiales. Si tu conto es hospite sur un differente servitor, tu non potera authenticar te ci. - title: Acceder a %{domain} + preamble_html: Aperi session con tu credentiales de %{domain}. Si tu conto es albergate sur un altere servitor, tu non potera aperir session hic. + title: Aperir session sur %{domain} sign_up: - manual_review: Le inscriptiones sur %{domain} passa per revision manual de nostre moderatores. Pro adjutar nos a processar tu registration, scribe un poco re te mesme e perque tu vole un conto sur %{domain}. - preamble: Con un conto sur iste servitor de Mastodon, tu potera sequer ulle altere persona in rete, sin reguardo de ubi lor conto es hospite. - title: Lassa que nos te configura sur %{domain}. + manual_review: Le inscriptiones sur %{domain} passa per un revision manual de nostre moderatores. Pro adjutar nos a processar tu inscription, per favor scribe un poco sur te e explica proque tu vole un conto sur %{domain}. + preamble: Con un conto sur iste servitor de Mastodon, tu potera sequer qualcunque altere persona sur le rete, independentemente de ubi su conto es albergate. + title: Lassa nos installar tu conto sur %{domain}. status: account_status: Stato del conto - confirming: Attendente esser completate email de confirmation. - functional: Tu conto es plenmente operative. - pending: Tu application es pendente de revision per nostre personal. Isto pote prender alcun tempore. Tu recipera un email si tu application es approbate. - redirecting_to: Tu conto es inactive perque illo es actualmente re-adressa a %{acct}. - self_destruct: Dum %{domain} va clauder, tu solo habera accesso limitate a tu conto. - view_strikes: Examinar le admonitiones passate contra tu conto - too_fast: Formulario inviate troppo velocemente, retenta. + confirming: Attendente le termination del confirmation del adresse de e-mail. + functional: Tu conto es completemente operative. + pending: Tu demanda attende le revision per nostre personal. Isto pote prender alcun tempore. Tu recipera un e-mail si tu demanda es approbate. + redirecting_to: Tu conto es inactive perque illo actualmente redirige a %{acct}. + self_destruct: Perque %{domain} va clauder, tu solo habera accesso limitate a tu conto. + view_strikes: Examinar le sanctiones passate contra tu conto + too_fast: Formulario inviate troppo rapidemente. Tenta lo de novo. use_security_key: Usar clave de securitate challenge: confirm: Continuar - hint_html: "Consilio: Nos non te demandara tu contrasigno ancora pro le proxime hora." + hint_html: "Consilio: Nos non te demandara tu contrasigno de novo in le proxime hora." invalid_password: Contrasigno non valide prompt: Confirma le contrasigno pro continuar crypto: errors: invalid_key: non es un clave Ed25519 o Curve25519 valide - invalid_signature: non es un valide firma Ed25519 + invalid_signature: non es un signatura Ed25519 valide date: formats: - default: "%b %d, %Y" - with_month_name: "%B %d, %Y" + default: "%d %b %Y" + with_month_name: "%d de %B %Y" datetime: distance_in_words: about_x_hours: "%{count}h" @@ -1144,44 +1144,44 @@ ia: about_x_years: "%{count}a" almost_x_years: "%{count}a" half_a_minute: Justo ora - less_than_x_minutes: "%{count} m" + less_than_x_minutes: "%{count}m" less_than_x_seconds: Justo ora over_x_years: "%{count}a" x_days: "%{count}d" - x_minutes: "%{count} m" + x_minutes: "%{count}m" x_months: "%{count}me" x_seconds: "%{count}s" deletes: - challenge_not_passed: Le informationes que tu ha inserite non era correcte + challenge_not_passed: Le informationes que tu ha inserite non es correcte confirm_password: Insere tu contrasigno actual pro verificar tu identitate - confirm_username: Insere tu actual contrasigno pro verificar tu identitate + confirm_username: Insere tu nomine de usator pro confirmar le procedura proceed: Deler le conto - success_msg: Tu conto esseva delite con successo + success_msg: Tu conto ha essite delite warning: - before: 'Insere tu nomine de usator pro confirmar le procedura:' - caches: Contente que ha essite in cache per altere servitores pote persister + before: 'Ante de continuar, per favor lege attentemente iste notas:' + caches: Le contento que altere servitores ha immagazinate in cache pote persister data_removal: Tu messages e altere datos essera removite permanentemente email_change_html: Tu pote cambiar tu adresse de e-mail sin deler tu conto - email_contact_html: Si illo ancora non arriva, tu pote inviar email a %{email} pro peter adjuta - email_reconfirmation_html: Si tu non recipe le email de confirmation, tu pote %{email} pro peter adjuta + email_reconfirmation_html: Si tu non recipe le e-mail de confirmation, tu pote politica de confidentialitate. + more_details_html: Pro plus detalios, vide le politica de confidentialitate. username_available: Tu nomine de usator essera disponibile novemente username_unavailable: Tu nomine de usator remanera indisponibile disputes: strikes: - action_taken: Action prendite - appeal: Facer appello - appeal_approved: Iste admonition ha essite annullate in appello e non es plus valide + action_taken: Mesura prendite + appeal: Appellar + appeal_approved: Iste sanction ha essite annullate in appello e non es plus valide appeal_rejected: Le appello ha essite rejectate appeal_submitted_at: Appello submittite appealed_msg: Tu appello ha essite submittite. Si es approbate, tu recipera notification. appeals: submit: Submitter appello approve_appeal: Approbar apello - associated_report: Signalation associate + associated_report: Le reporto associate created_at: Del data - description_html: Istes es le actiones prendite contra tu conto e le advertimentos que te ha essite inviate per le personal de %{instance}. + description_html: Istes es le mesuras prendite contra tu conto e le advertimentos que te ha essite inviate per le personal de %{instance}. recipient: Adressate a reject_appeal: Rejectar appello status: Message №%{id} @@ -1202,23 +1202,23 @@ ia: invalid_domain: non es un nomine de dominio valide edit_profile: basic_information: Information basic - hint_html: "Personalisa lo que le personas vide sur tu profilo public e presso tu messages. Il es plus probabile que altere personas te seque e interage con te quando tu ha un profilo compilate e un photo de profilo." + hint_html: "Personalisa lo que le personas vide sur tu profilo public e presso tu messages. Il es plus probabile que altere personas te seque e interage con te quando tu ha un profilo complete e un photo." other: Alteres errors: - '400': Le requesta que tu inviava era non valide o mal formate. - '403': Tu non ha le permisso pro acceder a iste pagina. + '400': Le requesta que tu ha inviate non es valide o es mal formate. + '403': Tu non ha le permission de acceder a iste pagina. '404': Le pagina que tu cerca non es ci. - '406': Iste pagina non es disponibile in le formato requirite. + '406': Iste pagina non es disponibile in le formato demandate. '410': Le pagina que tu cercava non plus existe ci. '422': content: Le verification de securitate ha fallite. Bloca tu le cookies? title: Falleva le verification de securitate - '429': Troppe requestas + '429': Troppo de requestas '500': - content: Nos lo regretta, ma alco errate eveniva sur nostre extremo. + content: Nos lo regretta, ma qualcosa non ha functionate de nostre latere. title: Iste pagina non es correcte - '503': Le pagina non poteva esser servite per un panna de servitor temporari. - noscript_html: A usar le application web Mastodon, activa JavaScript. In alternativa, tenta un del apps native de Mastodon pro tu platteforma. + '503': Le pagina non poteva esser servite a causa de un panna temporari del servitor. + noscript_html: Pro usar le application web Mastodon, es necessari activar JavaScript. Tu pote tamben probar un del apps native de Mastodon pro tu platteforma. existing_username_validator: not_found: impossibile trovar un usator local con ille nomine de usator not_found_multiple: non poteva trovar %{usernames} @@ -1226,9 +1226,9 @@ ia: archive_takeout: date: Data download: Discargar tu archivo - hint_html: Tu pote requirer un archivo de tu messages e medios cargate. Le datos exportate sera in le formato ActivityPub, legibile per ulle software conforme. + hint_html: Tu pote requestar un archivo de tu messages e files multimedial incargate. Le datos exportate essera in le formato ActivityPub, legibile per qualcunque software conforme. Tu pote requestar un archivo cata 7 dies. in_progress: Compilante tu archivo... - request: Pete tu archivo + request: Requestar tu archivo size: Dimension blocks: Tu ha blocate bookmarks: Marcapaginas @@ -1236,16 +1236,16 @@ ia: domain_blocks: Blocadas de dominio lists: Listas mutes: Tu ha silentiate - storage: Immagazinage de medios + storage: Immagazinage multimedial featured_tags: add_new: Adder nove errors: - limit: Tu ha jam consiliate le maxime numero de hashtags - hint_html: "Consilia tu plus importante hashtags sur tu profilo. Un grande instrumento pro tener tracia de tu labores creative e projectos de longe-tempore, le hashtags consiliate es monstrate prominentemente sur tu profilo e permitte accesso rapide a tu proprie messages." + limit: Tu ha jam mittite in evidentia le maxime numero de hashtags + hint_html: "Monstra tu plus importante hashtags sur tu profilo. Un excellente instrumento pro tener tracia de tu labores creative e projectos de longe termino, le hashtags que tu mitte in evidentia appare prominentemente sur tu profilo e permitte le accesso rapide a tu proprie messages." filters: contexts: account: Profilos - home: Pagina de initio e listas + home: Initio e listas notifications: Notificationes public: Chronologias public thread: Conversationes @@ -1253,11 +1253,11 @@ ia: add_keyword: Adder parola clave keywords: Parolas clave statuses: Messages individual - statuses_hint_html: Iste filtro se applica a seliger messages singule sin reguardo si illes concorda le parolas clave infra. Revide o remove le messages ab le filtro. + statuses_hint_html: Iste filtro se applica a un selection de messages individual, independentemente de si illos corresponde al parolas clave infra. Revide o remove messages del filtro. title: Modificar filtro errors: - deprecated_api_multiple_keywords: Iste parametros non pote esser cambiate ab iste application perque illos se applica a plus que un sol parola clave del filtro. Usa un application plus recente o le interfacie web. - invalid_context: Nulle o non valide contexto supplite + deprecated_api_multiple_keywords: Iste parametros non pote esser cambiate desde iste application perque illos se applica a plus de un parola clave del filtro. Usa un application plus recente o le interfacie web. + invalid_context: Contexto mancante o non valide index: contexts: Filtros in %{contexts} delete: Deler @@ -1271,8 +1271,8 @@ ia: one: "%{count} message" other: "%{count} messages" statuses_long: - one: "%{count} singule message celate" - other: "%{count} singule messages celate" + one: "%{count} message individual celate" + other: "%{count} messages individual celate" title: Filtros new: save: Salveguardar nove filtro @@ -1280,9 +1280,9 @@ ia: statuses: back_to_filter: Retro al filtro batch: - remove: Remover ab filtro + remove: Remover del filtro index: - hint: Iste filtro se applica pro seliger messages singule sin reguardo de altere criterios. Tu pote adder altere messages a iste filtro ab le interfacie web. + hint: Iste filtro se applica a un selection de messages individual, independentemente de altere criterios. Tu pote adder plus messages a iste filtro desde le interfacie web. title: Messages filtrate generic: all: Toto @@ -1290,53 +1290,53 @@ ia: one: "%{count} elemento sur iste pagina es seligite." other: Tote le %{count} elementos sur iste pagina es seligite. all_matching_items_selected_html: - one: "%{count} elemento concordante que tu cerca es seligite." - other: Tote le %{count} elementos concordante que tu cerca es seligite. + one: "%{count} elemento correspondente al recerca es seligite." + other: Tote le %{count} elementos correspondente al recerca es seligite. cancel: Cancellar changes_saved_msg: Cambios salveguardate con successo! confirm: Confirmar copy: Copiar delete: Deler deselect: Deseliger toto - none: Nemo + none: Necun order_by: Ordinar per save_changes: Salvar le cambios select_all_matching_items: - one: Selige %{count} elemento concordante tu recerca. - other: Selige %{count} elementos concordante tu recerca. + one: Selige %{count} elemento correspondente a tu recerca. + other: Selige %{count} elementos correspondente a tu recerca. today: hodie validation_errors: - one: Alco non es multo bon ancora! Controla le error infra - other: Alco non es multo bon ancora! Controla %{count} errores infra + one: Qualcosa ancora non es multo bon! Per favor controla le error infra + other: Qualcosa ancora non es multo bon! Per favor controla le %{count} errores infra imports: errors: empty: File CSV vacue incompatible_type: Incompatibile con le typo de importation seligite invalid_csv_file: 'File CSV non valide. Error: %{error}' - over_rows_processing_limit: contine plus que %{count} rangos - too_large: Le file es troppo longe + over_rows_processing_limit: contine plus de %{count} lineas + too_large: Le file es troppo grande failures: Fallimentos imported: Importate - mismatched_types_warning: Il appare que tu pote haber seligite le typo errate pro iste importation, controla duo vices. + mismatched_types_warning: Il pare que tu pote haber seligite le typo errate pro iste importation. Per favor reverifica lo. modes: - merge: Funder - merge_long: Mantene le registrationes existente e adde illos nove + merge: Fusionar + merge_long: Conservar le registros existente e adder noves overwrite: Superscriber overwrite_long: Reimplaciar registros actual con le noves overwrite_preambles: blocking_html: Tu es sur le puncto de reimplaciar tu lista de blocadas per usque a %{total_items} contos proveniente de %{filename}. - bookmarks_html: Tu va reimplaciar tu lista de blocadas per usque a %{total_items} contos proveniente de %{filename}. + bookmarks_html: Tu es sur le puncto de reimplaciar tu marcapaginas per usque a %{total_items} messages desde %{filename}. domain_blocking_html: Tu es sur le puncto de reimplaciar tu lista de blocadas de dominio per usque a %{total_items} dominios proveniente de %{filename}. - following_html: Tu va sequer usque %{total_items} contos de %{filename} e cessar de sequer ulle altere. - lists_html: Tu va reimplaciar tu lista con contentos de %{filename}. Usque %{total_items} contos sera addite a nove listas. - muting_html: Tu va reimplaciar tu lista de contos silentiate con usque %{total_items} contos ab %{filename}. + following_html: Tu es sur le puncto de sequer usque a %{total_items} contos de %{filename} e cessar de sequer tote le alteres. + lists_html: Tu es sur le puncto de reimplaciar tu listas per le contento de %{filename}. Usque a %{total_items} contos essera addite a nove listas. + muting_html: Tu es sur le puncto de reimplaciar tu lista de contos silentiate con usque a %{total_items} contos desde %{filename}. preambles: blocking_html: Tu es sur le puncto de blocar usque a %{total_items} contos a partir de %{filename}. - bookmarks_html: Tu va adder usque %{total_items} messages de %{filename} a tu marcapaginas. + bookmarks_html: Tu es sur le puncto de adder usque a %{total_items} messages desde %{filename} a tu marcapaginas. domain_blocking_html: Tu es sur le puncto de blocar usque a %{total_items} dominios a partir de %{filename}. - following_html: Tu va blocar usque a %{total_items} dominios ab %{filename}. - lists_html: Tu va adder usque %{total_items} contos ab %{filename} a tu lista. Nove listas sera create si il non ha lista a adder. - muting_html: Tu va silentiar usque %{total_items} contos ab %{filename}. + following_html: Tu es sur le puncto de sequer usque a %{total_items} contos desde %{filename}. + lists_html: Tu es sur le puncto de adder usque %{total_items} contos desde %{filename} a tu listas. Nove listas essera create si il non ha un lista al qual adder los. + muting_html: Tu es sur le puncto de silentiar usque a %{total_items} contos desde %{filename}. preface: Tu pote importar datos que tu ha exportate de un altere servitor, como un lista de personas que tu seque o bloca. recent_imports: Importationes recente states: @@ -1345,7 +1345,7 @@ ia: scheduled: Planificate unconfirmed: Non confirmate status: Stato - success: Tu datos era cargate con successo e sera processate in tempore debite + success: Tu datos ha essite correctemente incargate e essera tractate in tempore debite time_started: Initiate le titles: blocking: Importation de contos blocate @@ -1362,9 +1362,9 @@ ia: blocking: Lista de blocadas bookmarks: Marcapaginas domain_blocking: Lista de dominios blocate - following: Sequente lista + following: Lista de contos sequite lists: Listas - muting: Lista del silentiates + muting: Lista de contos silentiate upload: Incargar invites: delete: Disactivar @@ -1399,10 +1399,10 @@ ia: sign_in_token: codice de securitate de e-mail webauthn: claves de securitate description_html: Si tu vide activitate que tu non recognosce, considera de cambiar tu contrasigno e activar le authentication a duo factores. - empty: Nulle chronologia de authentication disponibile + empty: Nulle historia de authentication disponibile failed_sign_in_html: Tentativa de authentication fallite con %{method} ab %{ip} (%{browser}) - successful_sign_in_html: Apertura de session con successo con %{method} ab %{ip} (%{browser}) - title: Chronologia de authentication + successful_sign_in_html: Apertura de session succedite con %{method} desde %{ip} (%{browser}) + title: Historia de authentication mail_subscriptions: unsubscribe: action: Si, desubscriber @@ -1421,127 +1421,127 @@ ia: media_attachments: validations: images_and_video: Impossibile annexar un video a un message que jam contine imagines - not_ready: Impossibile annexar un video a un message que jam contine imagines. Retenta post un momento! - too_many: Impossibile annexar plus que 4 files + not_ready: Impossibile annexar files que non ha ancora essite processate. Retenta post un momento! + too_many: Impossibile annexar plus de 4 files migrations: - acct: Movite a + acct: Ha migrate a cancel: Cancellar redirection - cancel_explanation: Cancellar le redirection reactivara tu conto actual, ma non reportara sequaces que ha essite movite in ille conto. + cancel_explanation: Cancellar le redirection reactivara tu conto actual, ma non te retornara le sequitores que ha essite transferite al altere conto. cancelled_msg: Redirection cancellate con successo. errors: - already_moved: is the same account you have already moved to + already_moved: es le mesme conto al qual tu ha ja migrate missing_also_known_as: non es un alias de iste conto move_to_self: non pote esser le conto actual - not_found: non poterea esser trovate + not_found: non poteva esser trovate on_cooldown: Tu es in pausa - followers_count: Sequaces a tempore de mover - incoming_migrations: Movente ab un conto differente - incoming_migrations_html: Pro mover ab un altere conto a isto, primo tu debe crear un alias de conto. - moved_msg: Tu conto ora es redirigite a %{acct} e tu sequaces es movite super. - not_redirecting: Tu conto actualmente non es redirigite a ulle altere conto. - on_cooldown: Tu recentemente ha migrate tu conto. Iste function de novo sera disponibile in %{count} dies. + followers_count: Sequitores al momento de migration + incoming_migrations: Migrar de un altere conto + incoming_migrations_html: Pro migrar de un altere conto a iste, primo tu debe crear un alias de conto. + moved_msg: Tu conto es ora redirigite a %{acct} e le transferentia de tu sequitores es in curso. + not_redirecting: Tu conto actualmente non es redirigite a un altere conto. + on_cooldown: Tu ha recentemente migrate tu conto. Iste function essera disponibile de novo in %{count} dies. past_migrations: Migrationes passate - proceed_with_move: Mover sequaces + proceed_with_move: Transferer sequitores redirected_msg: Tu conto es ora redirigite a %{acct}. redirecting_to: Tu conto es redirigite a %{acct}. - set_redirect: Predefinir redirection + set_redirect: Definir redirection warning: - backreference_required: Le nove conto debe primo esser configurate pro referer se a isto - before: 'Ante de continuar, lege iste notas accuratemente:' - cooldown: Post le movimento il ha un periodo de pausa durante le qual tu non potera mover te ancora - disabled_account: Tu conto actual non sera plenmente usabile postea. Comocunque, tu habera accesso a exportation de datos e re-activation. - followers: Iste action movera tote le sequaces ab le conto actual al nove conto - only_redirect_html: In alternativa, tu pote solo superponer un redirection sur tu profilo. - other_data: Nulle altere datos sera movite automaticamente - redirect: Le profilo de tu conto actual sera actualisate con un aviso de redirection e sera excludite de recercas + backreference_required: Le nove conto debe primo esser configurate pro referer se a iste + before: 'Ante de continuar, lege attentemente iste notas:' + cooldown: Post le migration il ha un periodo de pausa durante le qual tu non potera migrar de novo + disabled_account: Tu conto actual non essera plenmente usabile postea. Nonobstante, tu habera accesso al exportation de datos e al reactivation. + followers: Iste action transferera tote le sequitores del conto actual al conto nove + only_redirect_html: Como alternativa, tu pote poner solmente un redirection sur tu profilo. + other_data: Nulle altere datos essera migrate automaticamente + redirect: Le profilo de tu conto actual essera actualisate con un aviso de redirection e excludite de recercas moderation: title: Moderation move_handler: carry_blocks_over_text: Iste usator ha cambiate de conto desde %{acct}, que tu habeva blocate. - carry_mutes_over_text: Iste usator moveva ab %{acct}, que tu habeva silentiate. - copy_account_note_text: 'Iste usator moveva ab %{acct}, ci era tu previe notas re ille:' + carry_mutes_over_text: Iste usator ha migrate de %{acct}, que tu habeva silentiate. + copy_account_note_text: 'Iste usator ha migrate de %{acct}, ecce tu previe notas sur iste persona:' navigation: - toggle_menu: Mutar menu + toggle_menu: Commutar menu notification_mailer: admin: report: - subject: "%{name} inviava un reporto" + subject: "%{name} ha inviate un reporto" sign_up: subject: "%{name} se ha inscribite" favourite: - body: 'Tu message era favorite per %{name}:' - subject: "%{name} favoriva tu message" - title: Nove preferito + body: 'Tu message ha essite marcate como favorite per %{name}:' + subject: "%{name} ha marcate tu message como favorite" + title: Nove favorite follow: body: "%{name} ora te seque!" subject: "%{name} ora te seque" title: Nove sequitor follow_request: - action: Gere requestas de sequer + action: Gerer requestas de sequimento body: "%{name} ha demandate de sequer te" - subject: 'Sequace pendente: %{name}' + subject: 'Sequitor pendente: %{name}' title: Nove requesta de sequimento mention: action: Responder - body: 'Tu era mentionate per %{name} in:' - subject: Tu ha essite mentionate per %{name} + body: "%{name} te ha mentionate in:" + subject: "%{name} te ha mentionate" title: Nove mention poll: - subject: Un inquesta de %{name} ha finite + subject: Un sondage de %{name} ha finite reblog: - body: 'Tu message ha essite impulsate per %{name}:' + body: "%{name} ha impulsate tu message:" subject: "%{name} ha impulsate tu message" title: Nove impulso status: - subject: "%{name} justo ha publicate" + subject: "%{name} ha publicate un message" update: subject: "%{name} ha modificate un message" notifications: - administration_emails: Avisos de email per administrator - email_events: Eventos pro avisos de email - email_events_hint: 'Selige eventos pro que tu vole reciper avisos:' + administration_emails: Notificationes per e-mail pro administratores + email_events: Eventos pro notificationes per e-mail + email_events_hint: 'Selige eventos pro le quales tu vole reciper notificationes:' number: human: decimal_units: - format: "%n%u" + format: "%n %u" units: - billion: B - million: M - quadrillion: Q - thousand: K - trillion: T + billion: mld + million: mln + quadrillion: bld + thousand: mil + trillion: bln otp_authentication: code_hint: Insere le codice generate per tu app de authentication pro confirmar - description_html: Si tu activa le authentication a duo factores per un app de authentication, le authentication requirera que tu es in possession de tu telephono, que generara testimonios pro facer te entrar. + description_html: Si tu activa le authentication a duo factores usante un app de authentication, le authentication requirera que tu es in possession de tu telephono, que generara tokens que tu debera inserer. enable: Activar - instructions_html: "Scande iste codice QR in Google Authenticator o un simile app TOTP sur tu telephono. Desde ora in avante, ille app generara testimonios que tu debera inserer quando tu te authenticara." - manual_instructions: 'Si tu non pote scander le codice QR e besonia de inserer lo manualmente, ecce le texto-simple secrete:' + instructions_html: "Scanna iste codice QR in Google Authenticator o un app TOTP simile sur tu telephono. Desde ora in avante, ille app generara tokens que tu debera inserer quando tu aperi session." + manual_instructions: 'Si tu non pote scannar le codice QR e debe inserer lo manualmente, ecce le secreto in texto simple:' setup: Configurar - wrong_code: Le codice inserite non era valide! Es tempore de servitor e tempore de apparato correcte? + wrong_code: Le codice inserite non es valide! Es le hora del servitor e del apparato correcte? pagination: - newer: Plus recente + newer: Plus nove next: Sequente - older: Plus vetere + older: Plus ancian prev: Previe truncate: "…" polls: errors: already_voted: Tu jam ha votate in iste sondage duplicate_options: contine elementos duplicate - duration_too_long: il es troppo lontan in le futuro - duration_too_short: il es troppo tosto + duration_too_long: es troppo lontan in le futuro + duration_too_short: es troppo tosto expired: Le sondage ha jam finite invalid_choice: Le option de voto eligite non existe over_character_limit: non pote esser plus longe que %{max} characteres cata un - self_vote: Tu non pote vota in tu proprie sondages - too_few_options: debe haber plus que un elemento - too_many_options: non pote continer plus que %{max} elementos + self_vote: Tu non pote votar in tu proprie sondages + too_few_options: debe haber plus de un elemento + too_many_options: non pote continer plus de %{max} elementos preferences: - other: Altere - posting_defaults: Publicationes predefinite + other: Alteres + posting_defaults: Parametros de publication predefinite public_timelines: Chronologias public privacy: - hint_html: "Personalisa como tu vole que tu profilo e tu messages a es trovate. Un varietate de functiones in Mastodon pote adjutar te attinger un plus large auditorio si activate. Prende un momento pro revider iste parametros pro assecurar te que illos se adapta a tu caso de uso." + hint_html: "Personalisa como tu vole que tu profilo e tu messages es trovate. Un varietate de functiones in Mastodon pote adjutar te a attinger un plus grande publico quando activate. Prende un momento pro revider iste parametros pro assecurar te que illos se adapta a tu besonios." privacy: Confidentialitate privacy_hint_html: Controla quanto tu vole divulgar pro le beneficio de alteres. Le gente discoperi profilos e applicationes interessante percurrente le profilos sequite per altere personas e vidente a partir de qual applicationes illos publica lor messages, ma tu pote preferer de mantener tal information private. reach: Portata @@ -1554,47 +1554,47 @@ ia: reactions: errors: limit_reached: Limite de reactiones differente attingite - unrecognized_emoji: non es un emoticone recognoscite + unrecognized_emoji: non es un emoji recognoscite redirects: - prompt: Si tu te fide de iste ligamine, clicca lo pro continuar. + prompt: Si tu te fide a iste ligamine, clicca sur illo pro continuar. title: Tu va lassar %{instance}. relationships: activity: Activitate del conto - confirm_follow_selected_followers: Desira tu vermente remover le sequaces seligite? - confirm_remove_selected_followers: Desira tu vermente remover le sequaces seligite? - confirm_remove_selected_follows: Desira tu vermente remover le sequaces seligite? + confirm_follow_selected_followers: Es tu secur que tu vole sequer le sequitores seligite? + confirm_remove_selected_followers: Es tu secur que tu vole remover le sequitores seligite? + confirm_remove_selected_follows: Es tu secur que tu vole cessar de sequer le contos seligite? dormant: Dormiente - follow_failure: Impossibile sequer alcun del contos seligite. - follow_selected_followers: Sequer le sequaces seligite - followers: Sequaces + follow_failure: Impossibile sequer alcunes del contos seligite. + follow_selected_followers: Sequer le sequitores seligite + followers: Sequitores following: Sequente invited: Invitate - last_active: Ultimo active + last_active: Ultime activitate most_recent: Plus recente - moved: Movite + moved: Migrate mutual: Mutue primary: Primari relationship: Relation - remove_selected_domains: Remover tote le sequaces ab le dominios seligite - remove_selected_followers: Remover le sequaces seligite + remove_selected_domains: Remover tote le sequitores del dominios seligite + remove_selected_followers: Remover le sequitores seligite remove_selected_follows: Non plus sequer le usatores seligite status: Stato del conto remote_follow: - missing_resource: Impossibile trovar le requirite re-adresse URL pro tu conto + missing_resource: Impossibile trovar le URL de redirection requirite pro tu conto reports: errors: - invalid_rules: non referentia regulas valide + invalid_rules: non face referentia a regulas valide rss: content_warning: 'Advertimento de contento:' descriptions: account: Messages public de @%{acct} - tag: 'Messages public plachettate #%{hashtag}' + tag: 'Messages public con hashtag #%{hashtag}' scheduled_statuses: over_daily_limit: Tu ha excedite le limite de %{limit} messages programmate pro hodie over_total_limit: Tu ha excedite le limite de %{limit} messages programmate too_soon: Le data programmate debe esser in le futuro self_destruct: - lead_html: Infortunatemente, %{domain} va clauder permanentemente. Si tu habeva un conto illac, tu non potera continuar a usar lo, ma tu pote ancora peter un salveguarda de tu datos. + lead_html: Infortunatemente, %{domain} tosto claudera permanentemente. Si tu habeva un conto illac, tu non potera continuar a usar lo, ma tu pote ancora requestar un copia de tu datos. title: Iste servitor va clauder sessions: activity: Ultime activitate @@ -1617,12 +1617,12 @@ ia: qq: QQ Browser safari: Safari uc_browser: UC Browser - unknown_browser: Navigator Incognite + unknown_browser: Navigator incognite weibo: Weibo current_session: Session actual date: Data description: "%{browser} sur %{platform}" - explanation: Il ha navigatores del web actualmente connexe a tu conto Mastodon. + explanation: Istes es le navigatores web actualmente in session sur tu conto Mastodon. ip: IP platforms: adobe_air: Adobe Air @@ -1641,29 +1641,29 @@ ia: revoke: Revocar revoke_success: Session revocate con successo title: Sessiones - view_authentication_history: Vider chronologia de authentication de tu conto + view_authentication_history: Vider le historia de authentication de tu conto settings: account: Conto account_settings: Parametros de conto aliases: Aliases de conto appearance: Apparentia authorized_apps: Apps autorisate - back: Tornar a Mastodon + back: Retornar a Mastodon delete: Deletion de conto development: Disveloppamento edit_profile: Modificar profilo export: Exportation de datos - featured_tags: Hashtags eminente + featured_tags: Hashtags in evidentia import: Importar import_and_export: Importar e exportar migrate: Migration de conto - notifications: Notificationes de e-mail + notifications: Notificationes per e-mail preferences: Preferentias profile: Profilo public relationships: Sequites e sequitores severed_relationships: Relationes rupte statuses_cleanup: Deletion de message automatic - strikes: Admonitiones de moderation + strikes: Sanctiones de moderation two_factor_authentication: Authentication a duo factores webauthn_authentication: Claves de securitate severed_relationships: @@ -1675,7 +1675,7 @@ ia: lost_followers: Sequitores perdite lost_follows: Sequites perdite preamble: Tu pote perder sequites e sequitores quando tu bloca un dominio o quando tu moderatores decide suspender un servitor remote. Quando isto occurre, tu potera discargar listas de relationes rumpite, a inspectar e eventualmente importar in un altere servitor. - purged: Le information re iste servitor ha essite purgate per le administratores de tu servitor. + purged: Le information sur iste servitor ha essite purgate per le administratores de tu servitor. type: Evento statuses: attached: @@ -1698,7 +1698,7 @@ ia: edited_at_html: Modificate le %{date} errors: in_reply_not_found: Le message a que tu tenta responder non pare exister. - open_in_web: Aperir in le web + open_in_web: Aperir sur le web over_character_limit: limite de characteres de %{max} excedite pin_errors: direct: Messages que es solo visibile a usatores mentionate non pote esser appunctate @@ -1714,11 +1714,11 @@ ia: other: "%{count} votos" vote: Votar show_more: Monstrar plus - show_thread: Monstrar argumento - title: '%{name}: "%{quote}"' + show_thread: Monstrar discussion + title: "%{name}: “%{quote}”" visibilities: direct: Directe - private: Solo-sequaces + private: Solmente sequitores private_long: Solmente monstrar a sequitores public: Public public_long: Omnes pote vider @@ -1729,22 +1729,22 @@ ia: enabled_hint: Dele automaticamente tu messages un vice que illos attinge un limine de etate specificate, salvo que illes concorda un del exceptiones infra exceptions: Exceptiones explanation: Pois que deler messages es un operation costose, isto es facite lentemente in le tempore quando le servitor non es alteremente occupate. Pro iste ration, tu messages pote esser delite un poco post que illos attinge le limine de etate. - ignore_favs: Ignorar favoritos + ignore_favs: Ignorar favorites ignore_reblogs: Ignorar impulsos - interaction_exceptions: Exceptiones basate super interactiones + interaction_exceptions: Exceptiones basate sur interactiones interaction_exceptions_explanation: Nota que il non ha garantia que le messages essera delite si illos va sub le limine de favorites o impulsos post haber lo superate un vice. keep_direct: Mantener le messages directe - keep_direct_hint: Non dele alcuno de tu messages directe - keep_media: Mantener messages con annexos de medios - keep_media_hint: Non dele alcuno de tu messages que ha annexos de medios - keep_pinned: Mantener messages appunctate - keep_pinned_hint: Non dele alcuno de tu messages appunctate + keep_direct_hint: Non dele alcun de tu messages directe + keep_media: Conservar messages con annexos multimedial + keep_media_hint: Non dele alcun de tu messages que ha annexos multimedial + keep_pinned: Conservar le messages fixate + keep_pinned_hint: Non dele alcun de tu messages fixate keep_polls: Mantener sondages - keep_polls_hint: Non dele ulle de tu sondages - keep_self_bookmark: Mantener messages que tu marcava con marcapaginas - keep_self_bookmark_hint: Non dele tu proprie messages si tu los ha marcate con marcapaginas - keep_self_fav: Mantene messages que tu favoriva - keep_self_fav_hint: Non dele tu proprie messages si tu los ha favorite + keep_polls_hint: Non dele alcun de tu sondages + keep_self_bookmark: Conservar le messages que tu ha in marcapaginas + keep_self_bookmark_hint: Non dele tu proprie messages si tu los ha addite al marcapaginas + keep_self_fav: Conservar tu messages favorite + keep_self_fav_hint: Non dele tu proprie messages si tu los ha marcate como favorite min_age: '1209600': 2 septimanas '15778476': 6 menses @@ -1755,17 +1755,17 @@ ia: '63113904': 2 annos '7889238': 3 menses min_age_label: Limine de etate - min_favs: Mantener messages favorite al minus - min_favs_hint: Non deler alcuno de tu messages que ha recipite al minus iste numero de favoritos. Lassar blanc pro deler messages sin reguardo de lor numero de favoritos - min_reblogs: Mantener messages impulsate al minus + min_favs: Conservar messages marcate como favorite al minus + min_favs_hint: Non dele alcun de tu messages que ha essite marcate como favorite al minus iste numero de vices. Lassa vacue pro deler messages independentemente de lor numero de marcas como favorite + min_reblogs: Conservar messages impulsate al minus min_reblogs_hint: Non dele alcun de tu messages que ha essite impulsate al minus iste numero de vices. Lassar vacue pro deler messages independentemente de lor numero de impulsos stream_entries: sensitive_content: Contento sensibile strikes: errors: - too_late: Es troppo tarde pro facer appello contra iste admonition + too_late: Es troppo tarde pro appellar contra iste sanction tags: - does_not_match_previous_name: non concorda le nomine previe + does_not_match_previous_name: non corresponde al nomine precedente themes: contrast: Mastodon (Alte contrasto) default: Mastodon (Obscur) @@ -1776,22 +1776,22 @@ ia: default: "%d %b %Y, %H:%M" month: "%b %Y" time: "%H:%M" - with_time_zone: "%b %d, %Y, %H:%M %Z" + with_time_zone: "%d %b %Y, %H:%M %Z" translation: errors: quota_exceeded: Le quota de utilisation del servitor pro le servicio de traduction ha essite excedite. - too_many_requests: Il ha habite troppe requestas al servicio de traduction recentemente. + too_many_requests: Il ha habite troppo de requestas al servicio de traduction recentemente. two_factor_authentication: add: Adder - disable: Disactivar 2FA + disable: Disactivar A2F disabled_success: Authentication a duo factores disactivate con successo edit: Modificar enabled: Le authentication a duo factores es activate enabled_success: Authentication a duo factores activate con successo generate_recovery_codes: Generar codices de recuperation - lost_recovery_codes: Le codices de recuperation te permitte de reganiar accesso a tu conto si tu perde tu telephono. Si tu ha perdite tu codices de recuperation, tu pote regenerar los ci. Tu vetere codices de recuperation sera invalidate. + lost_recovery_codes: Le codices de recuperation te permitte reganiar le accesso a tu conto si tu perde tu telephono. Si tu ha perdite tu codices de recuperation, tu pote regenerar los hic. Tu ancian codices de recuperation essera invalidate. methods: Methodos a duo factores - otp: App de authenticator + otp: App authenticator recovery_codes: Salveguardar codices de recuperation recovery_codes_regenerated: Codices de recuperation regenerate con successo recovery_instructions_html: Si tu perde le accesso a tu telephono, tu pote usar un del codices de recuperation hic infra pro reganiar le accesso a tu conto. Mantene le codices de recuperation secur. Per exemplo, tu pote imprimer los e guardar los con altere documentos importante. @@ -1799,33 +1799,33 @@ ia: user_mailer: appeal_approved: action: Parametros de conto - explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite approbate. Tu conto ha de novo un bon reputation. - subject: Tu appello ab %{date} ha essite approbate - subtitle: Tu conto es ancora un vice in regula. + explanation: Le appello contra le sanction del %{strike_date} contra tu conto, que tu ha submittite le %{appeal_date}, ha essite approbate. Tu conto es de bon reputation de novo. + subject: Tu appello del %{date} ha essite approbate + subtitle: Tu conto es de bon reputation de novo. title: Appello approbate appeal_rejected: - explanation: Le appello contra le admonition contra tu conto del %{strike_date}, que tu ha submittite le %{appeal_date}, ha essite rejectate. - subject: Tu appello ab %{date} ha essite rejectate + explanation: Le appello contra le sanction del %{strike_date} contra tu conto, que tu ha submittite le %{appeal_date}, ha essite rejectate. + subject: Tu appello del %{date} ha essite rejectate subtitle: Tu appello ha essite rejectate. title: Appello rejectate backup_ready: explanation: Tu ha requestate un copia de securitate complete de tu conto de Mastodon. - extra: Isto es preste pro discargar! + extra: Illo es ora preste pro discargar! subject: Tu archivo es preste pro discargar title: Discargar archivo failed_2fa: - details: 'Hic es le detalios del tentativa de initio de session:' + details: 'Ecce le detalios del tentativa de apertura de session:' explanation: Alcuno ha tentate aperir session a tu conto ma ha fornite un secunde factor de authentication non valide. further_actions_html: Si non se tractava de te, nos recommenda %{action} immediatemente perque illo pote esser compromittite. - subject: Fallimento del authentication de duo factores - title: Falleva le authentication de duo factores + subject: Fallimento de authentication del secunde factor + title: Ha fallite le authentication del secunde factor suspicious_sign_in: change_password: cambiar tu contrasigno - details: 'Hic es le detalios del initio de session:' - explanation: Nos ha detegite un initio de session a tu conto ab un nove adresse IP. + details: 'Ecce le detalios del apertura de session:' + explanation: Nos ha detegite un apertura de session sur tu conto desde un nove adresse IP. further_actions_html: Si non se tractava de te, nos recommenda %{action} immediatemente e activar le authentication bifactorial pro mantener tu conto secur. subject: Alcuno ha accedite a tu conto desde un nove adresse IP - title: Un nove initio de session + title: Un nove apertura de session warning: appeal: Submitter un appello appeal_description: Si tu crede que se tracta de un error, tu pote presentar un appello al personal de %{instance}. @@ -1840,9 +1840,9 @@ ia: silence: Tu pote ancora usar tu conto ma solmente le personas qui ja te seque videra tu messages sur iste servitor, e tu pote esser excludite de varie functiones de discoperta. Nonobstante, altere personas pote ancora sequer te manualmente. suspend: Tu non pote plus usar tu conto, e tu profilo e altere datos non es plus accessibile. Tu pote ancora aperir session pro requestar un copia de reserva de tu datos usque lor elimination in circa 30 dies. Nos retenera certe datos de base pro impedir que tu evade le suspension. reason: 'Ration:' - statuses: 'Message citate:' + statuses: 'Messages citate:' subject: - delete_statuses: Tu messages sur %{acct} esseva removite + delete_statuses: Tu messages sur %{acct} ha essite removite disable: Tu conto %{acct} ha essite gelate mark_statuses_as_sensitive: Tu messages sur %{acct} ha essite marcate como sensibile none: Advertimento pro %{acct} @@ -1858,7 +1858,7 @@ ia: silence: Conto limitate suspend: Conto suspendite welcome: - apps_android_action: Obtene lo sur Google Play + apps_android_action: Obtener lo sur Google Play apps_ios_action: Discargar sur le App Store apps_step: Discarga nostre applicationes official. apps_title: Applicationes de Mastodon @@ -1870,7 +1870,7 @@ ia: explanation: Ecce alcun consilios pro initiar feature_action: Apprender plus feature_audience: Mastodon te presenta le possibilitate unic de gerer tu audientia sin intermediarios. Mastodon, installate sur tu proprie infrastructura, te permitte sequer, e esser sequite per, personas sur qualcunque altere servitor Mastodon in linea, e necuno lo controla salvo tu. - feature_audience_title: Crea tu auditorio in fiducia + feature_audience_title: Crea tu audientia in confidentia feature_control: Tu sape melio lo que tu vole vider sur tu fluxo de initio. Nulle algorithmos o annuncios dissipa tu tempore. Seque quicinque sur qualcunque servitor Mastodon desde un sol conto, recipe lor messages in ordine chronologic, e face te un angulo del internet ubi tu te senti a casa. feature_control_title: Mantene le controlo de tu proprie chronologia feature_creativity: Mastodon supporta messages con audio, video e imagines, descriptiones de accessibilitate, sondages, advertimentos de contento, avatares con animation, emojis personalisate, controlo de retalio de miniaturas, e plus, pro adjutar te a exprimer te in linea. Que tu publica tu arte, tu musica o tu podcast, Mastodon existe pro te. @@ -1879,13 +1879,13 @@ ia: feature_moderation_title: Moderation como deberea esser follow_action: Sequer follow_step: Sequer personas interessante es le ration de esser de Mastodon. - follow_title: Personalisa tu fluxo de initio + follow_title: Personalisa tu fluxo principal follows_subtitle: Seque contos popular follows_title: Qui sequer - follows_view_more: Vider plus de personas a sequer + follows_view_more: Vider plus personas a sequer hashtags_recent_count: one: "%{people} persona in le passate duo dies" - other: "%{people} personas in le passate duo diea" + other: "%{people} personas in le passate duo dies" hashtags_subtitle: Explora le tendentias del passate 2 dies hashtags_title: Hashtags in tendentia hashtags_view_more: Vider plus de hashtags in tendentia @@ -1929,4 +1929,4 @@ ia: not_enabled: Tu ancora non ha activate WebAuthn not_supported: Iste navigator non supporta claves de securitate otp_required: Pro usar le claves de securitate activa prime le authentication de duo factores. - registered_on: Registrate le %{date} + registered_on: Inscribite le %{date} diff --git a/config/locales/lt.yml b/config/locales/lt.yml index c29218c1fe..9e60ddfe52 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -446,6 +446,7 @@ lt: instances: availability: title: Prieinamumas + warning: Paskutinis bandymas prisijungti prie šio serverio buvo nesėkmingas back_to_all: Visi back_to_limited: Apribotas back_to_warning: Įspėjimas @@ -488,7 +489,7 @@ lt: inbox_url: Perdavimo URL pending: Laukiama perdavimo patvirtinimo save_and_enable: Išsaugoti ir įjungti - setup: Sukurti perdavimo ryšį + setup: Nustatyti perdavimo ryšį status: Statusas title: Perdavimai report_notes: @@ -600,6 +601,8 @@ lt: elasticsearch_preset_single_node: action: Žiūrėti dokumentaciją message_html: Tavo Elasticsearch klasteris turi tik vieną mazgą, ES_PRESET turėtų būti nustatyta į single_node_cluster. + elasticsearch_running_check: + message_html: Nepavyko prijungti prie Elasticsearch. Patikrink, ar ji veikia, arba išjunk viso teksto paiešką. title: Administracija trends: allow: Leisti diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index d3237762ea..7e364889dd 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -3,40 +3,40 @@ ia: simple_form: hints: account: - discoverable: Tu messages public e tu profilo pote esser consiliate o recommendate in varie areas de Mastodon e tu profilo pote esser suggerite a altere usatores. + discoverable: Tu messages public e tu profilo pote esser mittite in evidentia o recommendate in varie areas de Mastodon e tu profilo pote esser suggerite a altere usatores. display_name: Tu prenomine e nomine de familia o tu pseudonymo. - fields: Tu pagina principal, pronomines, etate, toto lo que tu vole. - indexable: Tu messages public pote apparer in resultatos del recerca sur Mastodon. Illes qui ha interagite con tu messages totevia pote cercar les. + fields: Tu pagina principal, pronomines, etate, tote lo que tu vole. + indexable: Tu messages public pote apparer in le resultatos de recerca sur Mastodon. Le personas qui ha interagite con tu messages pote cercar los in omne caso. note: 'Tu pote @mentionar altere personas o #hashtags.' - show_collections: Le personas potera navigar per tu sequites e sequaces. Le personas potera navigar per tu sequites e sequaces. - unlocked: Le personas potera sequer te sin requestar approbation. Dismarca si tu desira revider le requestas de sequer e selige si acceptar o rejectar nove sequaces. + show_collections: Le personas potera percurrer tu sequites e sequitores. Le personas que tu seque videra que tu les seque in omne caso. + unlocked: Le personas potera sequer te sin requestar approbation. Dismarca si tu vole revider le requestas de sequimento e seliger si acceptar o rejectar nove sequitores. account_alias: - acct: Specifica le nomine_de_usator@dominio del conto ab que tu vole mover + acct: Specifica le nomine_de_usator@dominio del conto desde le qual tu vole migrar account_migration: - acct: Specifica le nomine_de_usator@dominio del conto a que tu vole mover + acct: Specifica le nomine_de_usator@dominio del conto al qual tu vole migrar account_warning_preset: - text: Tu pote usar le syntaxe de message, tal como URLs, hashtags e mentiones + text: Tu pote usar le syntaxe de messages, como URLs, hashtags e mentiones title: Optional. Non visibile al destinatario admin_account_action: - include_statuses: Le usator videra que messages ha causate le action o aviso de moderation - send_email_notification: Le usator recipera un explication de cosa eveniva con lor conto - text_html: Optional. Tu pote usar le syntaxe de message. Tu pote adder avisos preconfigurate pro sparniar tempore - type_html: Selige lo que tu vole facer con %{acct} + include_statuses: Le usator videra qual messages ha causate le action o advertimento de moderation + send_email_notification: Le usator recipera un explication de lo que ha evenite con su conto + text_html: Optional. Tu pote usar le syntaxe de messages. Tu pote adder advertimentos preconfigurate pro sparniar tempore + type_html: Selige lo que facer con %{acct} types: - disable: Impedir al usator de usar lor conto, sin deler o celar lor contentos. - none: Usar lo pro inviar un aviso al usator, sin discatenar ulle altere action. - sensitive: Fortiar tote le annexos multimedial de iste usator a esser signalate como sensibile. - silence: Impedir al usator de poter publicar messages con public visibilitate, celar lor messages e notificationes ab gente non sequente illes. Clauder tote le reportos contra iste conto. - suspend: Impedir ulle interaction de o a iste conto e deler su contentos. Reversibile intra 30 dies. Clauder tote le reportos contra iste conto. - warning_preset_id: Optional. Tu pote ancora adder personal texto a fin del preconfigurate + disable: Impedir al usator de usar su conto, sin deler o celar su contento. + none: Usa isto pro inviar un advertimento al usator, sin prender alcun altere mesura. + sensitive: Fortiar tote le annexos multimedial de iste usator a esser marcate como sensibile. + silence: Impedir al usator de publicar messages con visibilitate public, celante su messages e notificationes a qui non le seque. Claude tote le reportos contra iste conto. + suspend: Impedir tote interaction desde o verso iste conto e deler su contento. Reversibile intra 30 dies. Claude tote le reportos contra iste conto. + warning_preset_id: Optional. Tu pote ancora adder texto personalisate al fin del preconfigurate announcement: - all_day: Si marcate, solo le datas del campo tempore sera monstrate - ends_at: Le annuncio sera automaticamente obscurate a iste tempore - scheduled_at: Lassar blanc pro publicar le annuncio immediatemente - starts_at: Optional. In caso tu annuncio es ligate con un specific campo tempore - text: Tu pote usar le syntaxe de message. Presta attention al spatio que le annuncio occupara sur le schermo de usator + all_day: Si marcate, solmente le datas del intervallo de tempore essera monstrate + ends_at: Optional. Le annuncio essera automaticamente retirate del publication a iste tempore + scheduled_at: Lassa vacue pro publicar le annuncio immediatemente + starts_at: Optional. In caso que tu annuncio es ligate a un intervallo specific de tempore + text: Tu pote usar le syntaxe de messages. Presta attention al spatio que le annuncio occupara sur le schermo del usator appeal: - text: Tu pote solo appellar te un vice + text: Tu pote solo appellar contra un sanction un vice defaults: autofollow: Illes qui se inscribe per le invitation automaticamente devenira tu sequaces avatar: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px @@ -64,7 +64,7 @@ ia: username: Tu pote usar litteras, numeros e tractos de sublineamento whole_word: Quando le parola o expression clave es solo alphanumeric, illo sera solo applicate si illo concorda con tote le parola domain_allow: - domain: Iste dominio potera reportar datos ab iste servitor e le datos in ingresso ab illo sera processate e immagazinate + domain: Iste dominio potera extraher datos de iste servitor e le datos entrante de illo essera processate e immagazinate email_domain_block: domain: Isto pote esser le nomine de dominio que apparera in le adresse email o le registration MX que illo usa. Illos sera verificate durante le inscription. with_dns_records: Un tentativa sera facite pro resolver le registrationes de DNS del dominio date e le resultatos sera alsi blocate @@ -158,7 +158,7 @@ ia: text: Texto predefinite title: Titulo admin_account_action: - include_statuses: Includer messages reportate in le email + include_statuses: Includer le messages reportate in le e-mail send_email_notification: Notificar le usator per e-mail text: Advertimento personalisate type: Action diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml index 888e08b650..017acd0a53 100644 --- a/config/locales/simple_form.lv.yml +++ b/config/locales/simple_form.lv.yml @@ -78,6 +78,7 @@ lv: form_admin_settings: activity_api_enabled: Vietēji publicēto ziņu, aktīvo lietotāju un jauno reģistrāciju skaits nedēļas kopās app_icon: WEBP, PNG, GIF vai JPG. Mobilajās ierīcēs aizstāj noklusējuma lietotnes ikonu ar pielāgotu. + backups_retention_period: Lietotājiem ir iespēja izveidot savu ierakstu arhīvu lejupielādēšanai vēlāk. Kad iestatīta pozitīva vērtība, šie arhīvi tiks automātiski izdzēsti no krātuves pēc norādītā dienu skaita. bootstrap_timeline_accounts: Šie konti tiks piesprausti jauno lietotāju ieteikumu augšdaļā. closed_registrations_message: Tiek rādīts, kad reģistrēšanās ir slēgta custom_css: Vari lietot pielāgotus stilus Mastodon tīmekļa versijā. From 048f9b9d45b1d313de1d427956a2d354273a5d85 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:56:52 +0200 Subject: [PATCH 302/658] chore(deps): update dependency pghero to v3.5.0 (#30393) 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 597005b6b0..b5192c925a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -586,7 +586,7 @@ GEM pastel (0.8.0) tty-color (~> 0.5) pg (1.5.6) - pghero (3.4.1) + pghero (3.5.0) activerecord (>= 6) premailer (1.23.0) addressable From eef2cc054faaa808cb014d644317fbc398f6c75f Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Wed, 5 Jun 2024 10:06:06 +0200 Subject: [PATCH 303/658] Add url validation to Web::PushSubscription endpoints (#30540) --- app/models/web/push_subscription.rb | 2 +- spec/requests/api/v1/push/subscriptions_spec.rb | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb index a3a2ec3f03..1860f0aa3e 100644 --- a/app/models/web/push_subscription.rb +++ b/app/models/web/push_subscription.rb @@ -21,7 +21,7 @@ class Web::PushSubscription < ApplicationRecord has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription, dependent: nil - validates :endpoint, presence: true + validates :endpoint, presence: true, url: true validates :key_p256dh, presence: true validates :key_auth, presence: true diff --git a/spec/requests/api/v1/push/subscriptions_spec.rb b/spec/requests/api/v1/push/subscriptions_spec.rb index 700250ee2a..82ea308cd6 100644 --- a/spec/requests/api/v1/push/subscriptions_spec.rb +++ b/spec/requests/api/v1/push/subscriptions_spec.rb @@ -4,10 +4,11 @@ require 'rails_helper' describe 'API V1 Push Subscriptions' do let(:user) { Fabricate(:user) } + let(:endpoint) { 'https://fcm.googleapis.com/fcm/send/fiuH06a27qE:APA91bHnSiGcLwdaxdyqVXNDR9w1NlztsHb6lyt5WDKOC_Z_Q8BlFxQoR8tWFSXUIDdkyw0EdvxTu63iqamSaqVSevW5LfoFwojws8XYDXv_NRRLH6vo2CdgiN4jgHv5VLt2A8ah6lUX' } let(:create_payload) do { subscription: { - endpoint: 'https://fcm.googleapis.com/fcm/send/fiuH06a27qE:APA91bHnSiGcLwdaxdyqVXNDR9w1NlztsHb6lyt5WDKOC_Z_Q8BlFxQoR8tWFSXUIDdkyw0EdvxTu63iqamSaqVSevW5LfoFwojws8XYDXv_NRRLH6vo2CdgiN4jgHv5VLt2A8ah6lUX', + endpoint: endpoint, keys: { p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=', auth: 'eH_C8rq2raXqlcBVDa1gLg==', @@ -63,6 +64,18 @@ describe 'API V1 Push Subscriptions' do expect(endpoint_push_subscriptions.count) .to eq(1) end + + context 'with invalid endpoint URL' do + let(:endpoint) { 'app://example.foo' } + + it 'returns a validation error' do + subject + + expect(response).to have_http_status(422) + expect(endpoint_push_subscriptions.count).to eq(0) + expect(endpoint_push_subscription).to be_nil + end + end end describe 'PUT /api/v1/push/subscription' do From 20e490ba7e996033c549e6d1de7826b86ac2988d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:06:03 +0200 Subject: [PATCH 304/658] fix(deps): update dependency cssnano to v7.0.2 (#30560) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 94 +++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/yarn.lock b/yarn.lock index bad4fa01e7..7c36984cde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6715,9 +6715,9 @@ __metadata: languageName: node linkType: hard -"cssnano-preset-default@npm:^7.0.1": - version: 7.0.1 - resolution: "cssnano-preset-default@npm:7.0.1" +"cssnano-preset-default@npm:^7.0.2": + version: 7.0.2 + resolution: "cssnano-preset-default@npm:7.0.2" dependencies: browserslist: "npm:^4.23.0" css-declaration-sorter: "npm:^7.2.0" @@ -6729,12 +6729,12 @@ __metadata: postcss-discard-duplicates: "npm:^7.0.0" postcss-discard-empty: "npm:^7.0.0" postcss-discard-overridden: "npm:^7.0.0" - postcss-merge-longhand: "npm:^7.0.0" - postcss-merge-rules: "npm:^7.0.0" + postcss-merge-longhand: "npm:^7.0.1" + postcss-merge-rules: "npm:^7.0.1" postcss-minify-font-values: "npm:^7.0.0" postcss-minify-gradients: "npm:^7.0.0" postcss-minify-params: "npm:^7.0.0" - postcss-minify-selectors: "npm:^7.0.0" + postcss-minify-selectors: "npm:^7.0.1" postcss-normalize-charset: "npm:^7.0.0" postcss-normalize-display-values: "npm:^7.0.0" postcss-normalize-positions: "npm:^7.0.0" @@ -6747,11 +6747,11 @@ __metadata: postcss-ordered-values: "npm:^7.0.0" postcss-reduce-initial: "npm:^7.0.0" postcss-reduce-transforms: "npm:^7.0.0" - postcss-svgo: "npm:^7.0.0" - postcss-unique-selectors: "npm:^7.0.0" + postcss-svgo: "npm:^7.0.1" + postcss-unique-selectors: "npm:^7.0.1" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/bee65239d25de2ba87e85b4091cbc1cac9ba1b57c9f803dff5a71ea8a55a885045805840dd732be284c28cca6343dece37fc76d7096aba37cfa02eff2ee7714c + checksum: 10c0/7c66240594c1d7a0cc761e755236228b17251455aa57abc45be0631f7de0fde070c23b0e41ffa200d39cd8351718514217d8c7a8cc4f06b54289dc1d555dfeb2 languageName: node linkType: hard @@ -6765,14 +6765,14 @@ __metadata: linkType: hard "cssnano@npm:^7.0.0": - version: 7.0.1 - resolution: "cssnano@npm:7.0.1" + version: 7.0.2 + resolution: "cssnano@npm:7.0.2" dependencies: - cssnano-preset-default: "npm:^7.0.1" + cssnano-preset-default: "npm:^7.0.2" lilconfig: "npm:^3.1.1" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/8b17d13efe98ec2db2fbde9ca24e91842b9afe2f80becc5e4271ee1170d77cf73eed3cdc2f35ed51bacdeac763ff85db45ae8e9627a8862bf01d457a819a640e + checksum: 10c0/ad43d8c2e96fa1022fc5103064e4f08da3fdc5501a946d455edf0b81981b58cd06ad2d3f0c68d666e2b687c10c02ffbb383252aa34da0ddc3bd4d075f4a922c7 languageName: node linkType: hard @@ -13458,29 +13458,29 @@ __metadata: languageName: node linkType: hard -"postcss-merge-longhand@npm:^7.0.0": - version: 7.0.0 - resolution: "postcss-merge-longhand@npm:7.0.0" +"postcss-merge-longhand@npm:^7.0.1": + version: 7.0.1 + resolution: "postcss-merge-longhand@npm:7.0.1" dependencies: postcss-value-parser: "npm:^4.2.0" - stylehacks: "npm:^7.0.0" + stylehacks: "npm:^7.0.1" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/5f814f396a5107dcb5e74c2d4e55ebcd03b9bc2b3619ed7aea63a441854023ce349bc371d30aec1ac33a375139afac02709e7721e055b5e624701ac6576e8a10 + checksum: 10c0/e3d20502e65c82c9c4ba2e400bd093ee6b9c1b0019618ccd50eb40ef0e496206dd518c7e655a6986d780d5a52576e32e8f310d00484b15f67c77664a148df6eb languageName: node linkType: hard -"postcss-merge-rules@npm:^7.0.0": - version: 7.0.0 - resolution: "postcss-merge-rules@npm:7.0.0" +"postcss-merge-rules@npm:^7.0.1": + version: 7.0.1 + resolution: "postcss-merge-rules@npm:7.0.1" dependencies: browserslist: "npm:^4.23.0" caniuse-api: "npm:^3.0.0" cssnano-utils: "npm:^5.0.0" - postcss-selector-parser: "npm:^6.0.16" + postcss-selector-parser: "npm:^6.1.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/d9cb3a4e55db57aa7ba0bb1caefb82db93c8493d2b3db66091dae9d5794ca04729e660115765ff254d0eb960e4db037f6c5b92562b396b05216888d12acc08e0 + checksum: 10c0/d380c162327e7aad59efb55cfddc5ec4e3bf51d18b07b832fdd876505279bac3cb44511ada8e1e1992428dcec4f64c7ec457b6ff9109063c5a61abf4b59b7176 languageName: node linkType: hard @@ -13521,14 +13521,14 @@ __metadata: languageName: node linkType: hard -"postcss-minify-selectors@npm:^7.0.0": - version: 7.0.0 - resolution: "postcss-minify-selectors@npm:7.0.0" +"postcss-minify-selectors@npm:^7.0.1": + version: 7.0.1 + resolution: "postcss-minify-selectors@npm:7.0.1" dependencies: - postcss-selector-parser: "npm:^6.0.16" + postcss-selector-parser: "npm:^6.1.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/6baf0ea71b8dfd01bdb5b516d01aa00244c55cad8d9c674358d735cef2a6aca6586dd480d419cc8d3f470e6d2d7d19354592044f19766993caf9800d3d7e0d36 + checksum: 10c0/a8ff69657fb1808d8f0f105b13a416426902d6f498a4b7ebb3b96b4b9149e97ee2e2ad6cd98108e2f0b8f781701724e6c51e120e215cee3e40c2d7a2afac755a languageName: node linkType: hard @@ -13898,26 +13898,26 @@ __metadata: languageName: node linkType: hard -"postcss-svgo@npm:^7.0.0": - version: 7.0.0 - resolution: "postcss-svgo@npm:7.0.0" +"postcss-svgo@npm:^7.0.1": + version: 7.0.1 + resolution: "postcss-svgo@npm:7.0.1" dependencies: postcss-value-parser: "npm:^4.2.0" - svgo: "npm:^3.2.0" + svgo: "npm:^3.3.2" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/0e724069b5de83aa2b8f8a4746cb60cb663e0a8bbab0e4ba995649cb0562205af57d1f54b89fb90d8ae04a4b7ac3ac6e3751afffc3cff697cb19f7a36b71b195 + checksum: 10c0/7c7b177e6f4e2a3e9ada76d53afa02e08d900c8ac15600ba9daa80480269d538405e544bd8091bc5eb7529173a476896fad885a72a247258265424b29a9195ed languageName: node linkType: hard -"postcss-unique-selectors@npm:^7.0.0": - version: 7.0.0 - resolution: "postcss-unique-selectors@npm:7.0.0" +"postcss-unique-selectors@npm:^7.0.1": + version: 7.0.1 + resolution: "postcss-unique-selectors@npm:7.0.1" dependencies: - postcss-selector-parser: "npm:^6.0.16" + postcss-selector-parser: "npm:^6.1.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/33b532ad0e9271c5a379859e18adfdc72986bb538672cc0fbc06295d824f82dba3f7b57264e18a3214901bc5244ff5408d28b530374d24a088507287c7f520ce + checksum: 10c0/6352d71ce2f65265f545831c2ce3686bd71961d08a2247c545d717d93d23b1eb08bb986efc11194d31970eea4cb42207b9aa9a3f4666d75492a6cbf1493cf466 languageName: node linkType: hard @@ -16399,15 +16399,15 @@ __metadata: languageName: node linkType: hard -"stylehacks@npm:^7.0.0": - version: 7.0.0 - resolution: "stylehacks@npm:7.0.0" +"stylehacks@npm:^7.0.1": + version: 7.0.1 + resolution: "stylehacks@npm:7.0.1" dependencies: browserslist: "npm:^4.23.0" - postcss-selector-parser: "npm:^6.0.16" + postcss-selector-parser: "npm:^6.1.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/c1c0231974ab7922af3a535a9cb78bfe84997767da7defe111cc76d7f10c9e139fe8cb0f9d5bea87b0c0cc0166c82a6ec98a3d6242d7e29ef90adceecfd330ae + checksum: 10c0/538d5d9c6d84906efad3706f0873b85b67fa224f17759b122bad3d60f2928c31204fd658dd16ec952bf54858a3aeaef4643e040c04030459285ce1b13c4cae91 languageName: node linkType: hard @@ -16632,9 +16632,9 @@ __metadata: languageName: node linkType: hard -"svgo@npm:^3.2.0": - version: 3.2.0 - resolution: "svgo@npm:3.2.0" +"svgo@npm:^3.3.2": + version: 3.3.2 + resolution: "svgo@npm:3.3.2" dependencies: "@trysound/sax": "npm:0.2.0" commander: "npm:^7.2.0" @@ -16645,7 +16645,7 @@ __metadata: picocolors: "npm:^1.0.0" bin: svgo: ./bin/svgo - checksum: 10c0/28fa9061ccbcf2e3616d48d1feb613aaa05f8f290a329beb0e585914f1864385152934a7d4d683a4609fafbae3d51666633437c359c5c5ef74fb58ad09092a7c + checksum: 10c0/a6badbd3d1d6dbb177f872787699ab34320b990d12e20798ecae915f0008796a0f3c69164f1485c9def399e0ce0a5683eb4a8045e51a5e1c364bb13a0d9f79e1 languageName: node linkType: hard From 5f15a892fa4f01ef9bcf223ec6798b8a9d9945ed Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 5 Jun 2024 21:15:39 +0200 Subject: [PATCH 305/658] Add support for libvips in addition to ImageMagick (#30090) Co-authored-by: Claire --- .devcontainer/Dockerfile | 2 +- .github/actions/setup-ruby/action.yml | 2 +- .github/workflows/test-ruby.yml | 93 +++++++++++- Dockerfile | 4 +- Gemfile | 1 + Gemfile.lock | 3 + .../dimension/software_versions_dimension.rb | 13 +- app/models/concerns/attachmentable.rb | 2 +- app/models/preview_card.rb | 6 +- config/application.rb | 10 +- config/initializers/vips.rb | 27 ++++ lib/paperclip/blurhash_transcoder.rb | 20 ++- lib/paperclip/color_extractor.rb | 81 ++++++++-- lib/paperclip/vips_lazy_thumbnail.rb | 141 ++++++++++++++++++ spec/fixtures/files/monochrome.png | Bin 0 -> 9216 bytes spec/models/media_attachment_spec.rb | 10 +- 16 files changed, 392 insertions(+), 23 deletions(-) create mode 100644 config/initializers/vips.rb create mode 100644 lib/paperclip/vips_lazy_thumbnail.rb create mode 100644 spec/fixtures/files/monochrome.png diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 994a41d050..9d8fa2702d 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -9,7 +9,7 @@ RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSI # [Optional] Uncomment this section to install additional OS packages. RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg imagemagick libpam-dev + && apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg imagemagick libvips42 libpam-dev # [Optional] Uncomment this line to install additional gems. RUN gem install foreman diff --git a/.github/actions/setup-ruby/action.yml b/.github/actions/setup-ruby/action.yml index 3a6fba9402..3e232f134c 100644 --- a/.github/actions/setup-ruby/action.yml +++ b/.github/actions/setup-ruby/action.yml @@ -14,7 +14,7 @@ runs: shell: bash run: | sudo apt-get update - sudo apt-get install -y libicu-dev libidn11-dev ${{ inputs.additional-system-dependencies }} + sudo apt-get install -y libicu-dev libidn11-dev libvips42 ${{ inputs.additional-system-dependencies }} - name: Set up Ruby uses: ruby/setup-ruby@v1 diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 2bfa59e6b1..5f2297381a 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -133,7 +133,7 @@ jobs: uses: ./.github/actions/setup-ruby with: ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg imagemagick libpam-dev + additional-system-dependencies: ffmpeg libpam-dev - name: Load database schema run: './bin/rails db:create db:schema:load db:seed' @@ -148,6 +148,93 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + test-libvips: + name: Libvips tests + runs-on: ubuntu-24.04 + + needs: + - build + + services: + postgres: + image: postgres:14-alpine + env: + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + redis: + image: redis:7-alpine + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 6379:6379 + + env: + DB_HOST: localhost + DB_USER: postgres + DB_PASS: postgres + DISABLE_SIMPLECOV: ${{ matrix.ruby-version != '.ruby-version' }} + RAILS_ENV: test + ALLOW_NOPAM: true + PAM_ENABLED: true + PAM_DEFAULT_SERVICE: pam_test + PAM_CONTROLLED_SERVICE: pam_test_controlled + OIDC_ENABLED: true + OIDC_SCOPE: read + SAML_ENABLED: true + CAS_ENABLED: true + BUNDLE_WITH: 'pam_authentication test' + GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }} + MASTODON_USE_LIBVIPS: true + + strategy: + fail-fast: false + matrix: + ruby-version: + - '3.1' + - '3.2' + - '.ruby-version' + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + path: './' + name: ${{ github.sha }} + + - name: Expand archived asset artifacts + run: | + tar xvzf artifacts.tar.gz + + - name: Set up Ruby environment + uses: ./.github/actions/setup-ruby + with: + ruby-version: ${{ matrix.ruby-version}} + additional-system-dependencies: ffmpeg libpam-dev libyaml-dev + + - name: Load database schema + run: './bin/rails db:create db:schema:load db:seed' + + - run: bin/rspec --tag paperclip_processing + + - name: Upload coverage reports to Codecov + if: matrix.ruby-version == '.ruby-version' + uses: codecov/codecov-action@v4 + with: + files: coverage/lcov/mastodon.lcov + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + test-e2e: name: End to End testing runs-on: ubuntu-latest @@ -209,7 +296,7 @@ jobs: uses: ./.github/actions/setup-ruby with: ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg imagemagick + additional-system-dependencies: ffmpeg - name: Set up Javascript environment uses: ./.github/actions/setup-javascript @@ -329,7 +416,7 @@ jobs: uses: ./.github/actions/setup-ruby with: ruby-version: ${{ matrix.ruby-version}} - additional-system-dependencies: ffmpeg imagemagick + additional-system-dependencies: ffmpeg - name: Set up Javascript environment uses: ./.github/actions/setup-javascript diff --git a/Dockerfile b/Dockerfile index c90d5dc980..6d342db437 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,6 +43,8 @@ ENV \ # Apply Mastodon version information MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \ MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" \ +# Enable libvips + MASTODON_USE_LIBVIPS=true \ # Apply Mastodon static files and YJIT options RAILS_SERVE_STATIC_FILES=${RAILS_SERVE_STATIC_FILES} \ RUBY_YJIT_ENABLE=${RUBY_YJIT_ENABLE} \ @@ -97,7 +99,7 @@ RUN \ curl \ ffmpeg \ file \ - imagemagick \ + libvips42 \ libjemalloc2 \ patchelf \ procps \ diff --git a/Gemfile b/Gemfile index d9de331827..ca32d0cca1 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,7 @@ gem 'fog-core', '<= 2.4.0' gem 'fog-openstack', '~> 1.0', require: false gem 'kt-paperclip', '~> 7.2' gem 'md-paperclip-azure', '~> 2.2', require: false +gem 'ruby-vips', '~> 2.2', require: false gem 'active_model_serializers', '~> 0.10' gem 'addressable', '~> 2.8' diff --git a/Gemfile.lock b/Gemfile.lock index b5192c925a..bf5340a5b0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -763,6 +763,8 @@ GEM ruby-saml (1.16.0) nokogiri (>= 1.13.10) rexml + ruby-vips (2.2.1) + ffi (~> 1.12) ruby2_keywords (0.0.5) rubyzip (2.3.2) rufus-scheduler (3.9.1) @@ -1023,6 +1025,7 @@ DEPENDENCIES rubocop-rspec ruby-prof ruby-progressbar (~> 1.13) + ruby-vips (~> 2.2) rubyzip (~> 2.3) sanitize (~> 6.0) scenic (~> 1.7) diff --git a/app/lib/admin/metrics/dimension/software_versions_dimension.rb b/app/lib/admin/metrics/dimension/software_versions_dimension.rb index 97cdaf589e..9dd0d393f9 100644 --- a/app/lib/admin/metrics/dimension/software_versions_dimension.rb +++ b/app/lib/admin/metrics/dimension/software_versions_dimension.rb @@ -10,7 +10,7 @@ class Admin::Metrics::Dimension::SoftwareVersionsDimension < Admin::Metrics::Dim protected def perform_query - [mastodon_version, ruby_version, postgresql_version, redis_version, elasticsearch_version].compact + [mastodon_version, ruby_version, postgresql_version, redis_version, elasticsearch_version, libvips_version].compact end def mastodon_version @@ -71,6 +71,17 @@ class Admin::Metrics::Dimension::SoftwareVersionsDimension < Admin::Metrics::Dim nil end + def libvips_version + return unless Rails.configuration.x.use_vips + + { + key: 'libvips', + human_key: 'libvips', + value: Vips.version_string, + human_value: Vips.version_string, + } + end + def redis_info @redis_info ||= if redis.is_a?(Redis::Namespace) redis.redis.info diff --git a/app/models/concerns/attachmentable.rb b/app/models/concerns/attachmentable.rb index f457f5822b..a83e178fc4 100644 --- a/app/models/concerns/attachmentable.rb +++ b/app/models/concerns/attachmentable.rb @@ -69,7 +69,7 @@ module Attachmentable original_extension = Paperclip::Interpolations.extension(attachment, :original) proper_extension = extensions_for_mime_type.first.to_s extension = extensions_for_mime_type.include?(original_extension) ? original_extension : proper_extension - extension = 'jpeg' if extension == 'jpe' + extension = 'jpeg' if ['jpe', 'jfif'].include?(extension) extension end diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index 11fdd9d88a..cbfc393786 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -57,7 +57,11 @@ class PreviewCard < ApplicationRecord has_one :trend, class_name: 'PreviewCardTrend', inverse_of: :preview_card, dependent: :destroy belongs_to :author_account, class_name: 'Account', optional: true - has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false + has_attached_file :image, + processors: [Rails.configuration.x.use_vips ? :lazy_thumbnail : :thumbnail, :blurhash_transcoder], + styles: ->(f) { image_styles(f) }, + convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, + validate_media_type: false validates :url, presence: true, uniqueness: true, url: true validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES diff --git a/config/application.rb b/config/application.rb index a8e313069d..069eb37740 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,7 +27,7 @@ require_relative '../lib/sanitize_ext/sanitize_config' require_relative '../lib/redis/namespace_extensions' require_relative '../lib/paperclip/url_generator_extensions' require_relative '../lib/paperclip/attachment_extensions' -require_relative '../lib/paperclip/lazy_thumbnail' + require_relative '../lib/paperclip/gif_transcoder' require_relative '../lib/paperclip/media_type_spoof_detector_extensions' require_relative '../lib/paperclip/transcoder' @@ -100,6 +100,14 @@ module Mastodon config.before_configuration do require 'mastodon/redis_config' + + config.x.use_vips = ENV['MASTODON_USE_LIBVIPS'] == 'true' + + if config.x.use_vips + require_relative '../lib/paperclip/vips_lazy_thumbnail' + else + require_relative '../lib/paperclip/lazy_thumbnail' + end end config.to_prepare do diff --git a/config/initializers/vips.rb b/config/initializers/vips.rb new file mode 100644 index 0000000000..25a17b2a17 --- /dev/null +++ b/config/initializers/vips.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +if Rails.configuration.x.use_vips + ENV['VIPS_BLOCK_UNTRUSTED'] = 'true' + + require 'vips' + + abort('Incompatible libvips version, please install libvips >= 8.13') unless Vips.at_least_libvips?(8, 13) + + Vips.block('VipsForeign', true) + + %w( + VipsForeignLoadNsgif + VipsForeignLoadJpeg + VipsForeignLoadPng + VipsForeignLoadWebp + VipsForeignLoadHeif + VipsForeignSavePng + VipsForeignSaveSpng + VipsForeignSaveJpeg + VipsForeignSaveWebp + ).each do |operation| + Vips.block(operation, false) + end + + Vips.block_untrusted(true) +end diff --git a/lib/paperclip/blurhash_transcoder.rb b/lib/paperclip/blurhash_transcoder.rb index c22c20c57a..e9cecef50c 100644 --- a/lib/paperclip/blurhash_transcoder.rb +++ b/lib/paperclip/blurhash_transcoder.rb @@ -5,12 +5,26 @@ module Paperclip def make return @file unless options[:style] == :small || options[:blurhash] - pixels = convert(':source -depth 8 RGB:-', source: File.expand_path(@file.path)).unpack('C*') - geometry = options.fetch(:file_geometry_parser).from_file(@file) + width, height, data = blurhash_params + # Guard against segfaults if data has unexpected size + raise RangeError("Invalid image data size (expected #{width * height * 3}, got #{data.size})") if data.size != width * height * 3 # TODO: should probably be another exception type - attachment.instance.blurhash = Blurhash.encode(geometry.width, geometry.height, pixels, **(options[:blurhash] || {})) + attachment.instance.blurhash = Blurhash.encode(width, height, data, **(options[:blurhash] || {})) @file end + + private + + def blurhash_params + if Rails.configuration.x.use_vips + image = Vips::Image.thumbnail(@file.path, 100) + [image.width, image.height, image.colourspace(:srgb).extract_band(0, n: 3).to_a.flatten] + else + pixels = convert(':source -depth 8 RGB:-', source: File.expand_path(@file.path)).unpack('C*') + geometry = options.fetch(:file_geometry_parser).from_file(@file) + [geometry.width, geometry.height, pixels] + end + end end end diff --git a/lib/paperclip/color_extractor.rb b/lib/paperclip/color_extractor.rb index d2f7e7c602..b5992f90bc 100644 --- a/lib/paperclip/color_extractor.rb +++ b/lib/paperclip/color_extractor.rb @@ -7,15 +7,10 @@ module Paperclip MIN_CONTRAST = 3.0 ACCENT_MIN_CONTRAST = 2.0 FREQUENCY_THRESHOLD = 0.01 + BINS = 10 def make - depth = 8 - - # Determine background palette by getting colors close to the image's edge only - background_palette = palette_from_histogram(convert(':source -alpha set -gravity Center -region 75%x75% -fill None -colorize 100% -alpha transparent +region -format %c -colors :quantity -depth :depth histogram:info:', source: File.expand_path(@file.path), quantity: 10, depth: depth), 10) - - # Determine foreground palette from the whole image - foreground_palette = palette_from_histogram(convert(':source -format %c -colors :quantity -depth :depth histogram:info:', source: File.expand_path(@file.path), quantity: 10, depth: depth), 10) + background_palette, foreground_palette = Rails.configuration.x.use_vips ? palettes_from_libvips : palettes_from_imagemagick background_color = background_palette.first || foreground_palette.first foreground_colors = [] @@ -78,6 +73,75 @@ module Paperclip private + def palettes_from_libvips + image = downscaled_image + block_edge_dim = (image.height * 0.25).floor + line_edge_dim = (image.width * 0.25).floor + + edge_image = begin + top = image.crop(0, 0, image.width, block_edge_dim) + bottom = image.crop(0, image.height - block_edge_dim, image.width, block_edge_dim) + left = image.crop(0, block_edge_dim, line_edge_dim, image.height - (block_edge_dim * 2)) + right = image.crop(image.width - line_edge_dim, block_edge_dim, line_edge_dim, image.height - (block_edge_dim * 2)) + top.join(bottom, :vertical).join(left, :horizontal).join(right, :horizontal) + end + + background_palette = palette_from_image(edge_image) + foreground_palette = palette_from_image(image) + [background_palette, foreground_palette] + end + + def palettes_from_imagemagick + depth = 8 + + # Determine background palette by getting colors close to the image's edge only + background_palette = palette_from_im_histogram(convert(':source -alpha set -gravity Center -region 75%x75% -fill None -colorize 100% -alpha transparent +region -format %c -colors :quantity -depth :depth histogram:info:', source: File.expand_path(@file.path), quantity: 10, depth: depth), 10) + + # Determine foreground palette from the whole image + foreground_palette = palette_from_im_histogram(convert(':source -format %c -colors :quantity -depth :depth histogram:info:', source: File.expand_path(@file.path), quantity: 10, depth: depth), 10) + [background_palette, foreground_palette] + end + + def downscaled_image + image = Vips::Image.new_from_file(@file.path, access: :random).thumbnail_image(100) + + image.colourspace(:srgb).extract_band(0, n: 3) + end + + def palette_from_image(image) + # `hist_find_ndim` will create a BINS×BINS×BINS 3D histogram of the image + # represented as an image of size BINS×BINS with `BINS` bands. + # The number of occurrences of a color (r, g, b) is thus encoded in band `b` at pixel position `(r, g)` + histogram = image.hist_find_ndim(bins: BINS) + + # `histogram.max` returns an array of maxima with their pixel positions, but we don't know in which + # band they are + _, colors = histogram.max(size: 10, out_array: true, x_array: true, y_array: true) + + colors['out_array'].zip(colors['x_array'], colors['y_array']).map do |v, x, y| + rgb_from_xyv(histogram, x, y, v) + end.reverse + end + + # rubocop:disable Naming/MethodParameterName + def rgb_from_xyv(image, x, y, v) + pixel = image.getpoint(x, y) + + # Unfortunately, we only have the first 2 dimensions, so try to + # guess the third one by looking up the value + + # NOTE: this means that if multiple bins with the same `r` and `g` + # components have the same number of occurrences, we will always return + # the one with the lowest `b` value. This means that in case of a tie, + # we will return the same color twice and skip the ones it tied with. + z = pixel.find_index(v) + + r = (x + 0.5) * 256 / BINS + g = (y + 0.5) * 256 / BINS + b = (z + 0.5) * 256 / BINS + ColorDiff::Color::RGB.new(r, g, b) + end + def w3c_contrast(color1, color2) luminance1 = (color1.to_xyz.y * 0.01) + 0.05 luminance2 = (color2.to_xyz.y * 0.01) + 0.05 @@ -89,7 +153,6 @@ module Paperclip end end - # rubocop:disable Naming/MethodParameterName def rgb_to_hsl(r, g, b) r /= 255.0 g /= 255.0 @@ -170,7 +233,7 @@ module Paperclip ColorDiff::Color::RGB.new(*hsl_to_rgb(hue, saturation, light)) end - def palette_from_histogram(result, quantity) + def palette_from_im_histogram(result, quantity) frequencies = result.scan(/([0-9]+):/).flatten.map(&:to_f) hex_values = result.scan(/\#([0-9A-Fa-f]{6,8})/).flatten total_frequencies = frequencies.sum.to_f diff --git a/lib/paperclip/vips_lazy_thumbnail.rb b/lib/paperclip/vips_lazy_thumbnail.rb new file mode 100644 index 0000000000..06d99bf79d --- /dev/null +++ b/lib/paperclip/vips_lazy_thumbnail.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +module Paperclip + class LazyThumbnail < Paperclip::Processor + GIF_MAX_FPS = 60 + GIF_MAX_FRAMES = 3000 + GIF_PALETTE_COLORS = 32 + + ALLOWED_FIELDS = %w( + icc-profile-data + ).freeze + + class PixelGeometryParser + def self.parse(current_geometry, pixels) + width = Math.sqrt(pixels * (current_geometry.width.to_f / current_geometry.height)).round.to_i + height = Math.sqrt(pixels * (current_geometry.height.to_f / current_geometry.width)).round.to_i + + Paperclip::Geometry.new(width, height) + end + end + + def initialize(file, options = {}, attachment = nil) + super + + @crop = options[:geometry].to_s[-1, 1] == '#' + @current_geometry = options.fetch(:file_geometry_parser, Geometry).from_file(@file) + @target_geometry = options[:pixels] ? PixelGeometryParser.parse(@current_geometry, options[:pixels]) : options.fetch(:string_geometry_parser, Geometry).parse(options[:geometry].to_s) + @format = options[:format] + @current_format = File.extname(@file.path) + @basename = File.basename(@file.path, @current_format) + + correct_current_format! + end + + def make + return File.open(@file.path) unless needs_convert? + + dst = TempfileFactory.new.generate([@basename, @format ? ".#{@format}" : @current_format].join) + + if preserve_animation? + if @target_geometry.nil? || (@current_geometry.width <= @target_geometry.width && @current_geometry.height <= @target_geometry.height) + target_width = 'iw' + target_height = 'ih' + else + scale = [@target_geometry.width.to_f / @current_geometry.width, @target_geometry.height.to_f / @current_geometry.height].min + target_width = (@current_geometry.width * scale).round + target_height = (@current_geometry.height * scale).round + end + + # The only situation where we use crop on GIFs is cropping them to a square + # aspect ratio, such as for avatars, so this is the only special case we + # implement. If cropping ever becomes necessary for other situations, this will + # need to be expanded. + crop_width = crop_height = [target_width, target_height].min if @target_geometry&.square? + + filter = begin + if @crop + "scale=#{target_width}:#{target_height}:force_original_aspect_ratio=increase,crop=#{crop_width}:#{crop_height}" + else + "scale=#{target_width}:#{target_height}:force_original_aspect_ratio=decrease" + end + end + + command = Terrapin::CommandLine.new(Rails.configuration.x.ffmpeg_binary, '-nostdin -i :source -map_metadata -1 -fpsmax :max_fps -frames:v :max_frames -filter_complex :filter -y :destination', logger: Paperclip.logger) + command.run({ source: @file.path, filter: "#{filter},split[a][b];[a]palettegen=max_colors=#{GIF_PALETTE_COLORS}[p];[b][p]paletteuse=dither=bayer", max_fps: GIF_MAX_FPS, max_frames: GIF_MAX_FRAMES, destination: dst.path }) + else + transformed_image.write_to_file(dst.path, **save_options) + end + + dst + rescue Terrapin::ExitStatusError => e + raise Paperclip::Error, "Error while optimizing #{@basename}: #{e}" + rescue Terrapin::CommandNotFoundError + raise Paperclip::Errors::CommandNotFoundError, 'Could not run the `ffmpeg` command. Please install ffmpeg.' + end + + private + + def correct_current_format! + # If the attachment was uploaded through a base64 payload, the tempfile + # will not have a file extension. It could also have the wrong file extension, + # depending on what the uploaded file was named. We correct for this in the final + # file name, which is however not yet physically in place on the temp file, so we + # need to use it here. Mind that this only reliably works if this processor is + # the first in line and we're working with the original, unmodified file. + @current_format = File.extname(attachment.instance_read(:file_name)) + end + + def transformed_image + # libvips has some optimizations for resizing an image on load. If we don't need to + # resize the image, we have to load it a different way. + if @target_geometry.nil? + Vips::Image.new_from_file(preserve_animation? ? "#{@file.path}[n=-1]" : @file.path, access: :sequential).copy.mutate do |mutable| + (mutable.get_fields - ALLOWED_FIELDS).each do |field| + mutable.remove!(field) + end + end + else + Vips::Image.thumbnail(@file.path, @target_geometry.width, height: @target_geometry.height, **thumbnail_options).mutate do |mutable| + (mutable.get_fields - ALLOWED_FIELDS).each do |field| + mutable.remove!(field) + end + end + end + end + + def thumbnail_options + @crop ? { crop: :centre } : { size: :down } + end + + def save_options + case @format + when 'jpg' + { Q: 90, interlace: true } + else + {} + end + end + + def preserve_animation? + @format == 'gif' || (@format.blank? && @current_format == '.gif') + end + + def needs_convert? + needs_different_geometry? || needs_different_format? || needs_metadata_stripping? + end + + def needs_different_geometry? + (options[:geometry] && @current_geometry.width != @target_geometry.width && @current_geometry.height != @target_geometry.height) || + (options[:pixels] && @current_geometry.width * @current_geometry.height > options[:pixels]) + end + + def needs_different_format? + @format.present? && @current_format != ".#{@format}" + end + + def needs_metadata_stripping? + @attachment.instance.respond_to?(:local?) && @attachment.instance.local? + end + end +end diff --git a/spec/fixtures/files/monochrome.png b/spec/fixtures/files/monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..fa36101cad383620a94c627add680bff8d38c3c2 GIT binary patch literal 9216 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 Rr%5lkm>5{<*TdW*{s*~%YhM5W literal 0 HcmV?d00001 diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb index 1b9a13c38c..221645ac5a 100644 --- a/spec/models/media_attachment_spec.rb +++ b/spec/models/media_attachment_spec.rb @@ -139,6 +139,12 @@ RSpec.describe MediaAttachment, :paperclip_processing do it_behaves_like 'static 600x400 image', 'image/png', '.png' end + describe 'monochrome jpg' do + let(:media) { Fabricate(:media_attachment, file: attachment_fixture('monochrome.png')) } + + it_behaves_like 'static 600x400 image', 'image/png', '.png' + end + describe 'webp' do let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.webp')) } @@ -203,7 +209,9 @@ RSpec.describe MediaAttachment, :paperclip_processing do expect(media.type).to eq 'audio' expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102) expect(media.thumbnail.present?).to be true - expect(media.file.meta['colors']['background']).to eq '#3088d4' + + # NOTE: Our libvips and ImageMagick implementations currently have different results + expect(media.file.meta['colors']['background']).to eq(ENV['MASTODON_USE_LIBVIPS'] ? '#268cd9' : '#3088d4') expect(media.file_file_name).to_not eq 'boop.ogg' end end From 4655be0da6c0f9a58f4d09a32189cbe5619c42d1 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Wed, 5 Jun 2024 21:16:47 +0200 Subject: [PATCH 306/658] Fix add validation to webpush subscription keys (#30542) --- app/models/web/push_subscription.rb | 2 + app/validators/web_push_key_validator.rb | 11 +++++ .../web_push_subscription_fabricator.rb | 8 +++- .../api/v1/push/subscriptions_spec.rb | 47 +++++++++++++++---- 4 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 app/validators/web_push_key_validator.rb diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb index 1860f0aa3e..b482ad3afe 100644 --- a/app/models/web/push_subscription.rb +++ b/app/models/web/push_subscription.rb @@ -25,6 +25,8 @@ class Web::PushSubscription < ApplicationRecord validates :key_p256dh, presence: true validates :key_auth, presence: true + validates_with WebPushKeyValidator + delegate :locale, to: :associated_user def encrypt(payload) diff --git a/app/validators/web_push_key_validator.rb b/app/validators/web_push_key_validator.rb new file mode 100644 index 0000000000..a8ad5c9c6b --- /dev/null +++ b/app/validators/web_push_key_validator.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class WebPushKeyValidator < ActiveModel::Validator + def validate(subscription) + begin + Webpush::Encryption.encrypt('validation_test', subscription.key_p256dh, subscription.key_auth) + rescue ArgumentError, OpenSSL::PKey::EC::Point::Error + subscription.errors.add(:base, I18n.t('crypto.errors.invalid_key')) + end + end +end diff --git a/spec/fabricators/web_push_subscription_fabricator.rb b/spec/fabricators/web_push_subscription_fabricator.rb index baffdbf83e..6b4028342c 100644 --- a/spec/fabricators/web_push_subscription_fabricator.rb +++ b/spec/fabricators/web_push_subscription_fabricator.rb @@ -2,6 +2,10 @@ Fabricator(:web_push_subscription, from: Web::PushSubscription) do endpoint Faker::Internet.url - key_p256dh Faker::Internet.password - key_auth Faker::Internet.password + key_p256dh do + curve = OpenSSL::PKey::EC.generate('prime256v1') + ecdh_key = curve.public_key.to_bn.to_s(2) + Base64.urlsafe_encode64(ecdh_key) + end + key_auth { Base64.urlsafe_encode64(Random.new.bytes(16)) } end diff --git a/spec/requests/api/v1/push/subscriptions_spec.rb b/spec/requests/api/v1/push/subscriptions_spec.rb index 82ea308cd6..54ef5a13ad 100644 --- a/spec/requests/api/v1/push/subscriptions_spec.rb +++ b/spec/requests/api/v1/push/subscriptions_spec.rb @@ -5,14 +5,17 @@ require 'rails_helper' describe 'API V1 Push Subscriptions' do let(:user) { Fabricate(:user) } let(:endpoint) { 'https://fcm.googleapis.com/fcm/send/fiuH06a27qE:APA91bHnSiGcLwdaxdyqVXNDR9w1NlztsHb6lyt5WDKOC_Z_Q8BlFxQoR8tWFSXUIDdkyw0EdvxTu63iqamSaqVSevW5LfoFwojws8XYDXv_NRRLH6vo2CdgiN4jgHv5VLt2A8ah6lUX' } + let(:keys) do + { + p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=', + auth: 'eH_C8rq2raXqlcBVDa1gLg==', + } + end let(:create_payload) do { subscription: { endpoint: endpoint, - keys: { - p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=', - auth: 'eH_C8rq2raXqlcBVDa1gLg==', - }, + keys: keys, }, }.with_indifferent_access end @@ -37,6 +40,16 @@ describe 'API V1 Push Subscriptions' do let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + shared_examples 'validation error' do + it 'returns a validation error' do + subject + + expect(response).to have_http_status(422) + expect(endpoint_push_subscriptions.count).to eq(0) + expect(endpoint_push_subscription).to be_nil + end + end + describe 'POST /api/v1/push/subscription' do subject { post '/api/v1/push/subscription', params: create_payload, headers: headers } @@ -68,13 +81,29 @@ describe 'API V1 Push Subscriptions' do context 'with invalid endpoint URL' do let(:endpoint) { 'app://example.foo' } - it 'returns a validation error' do - subject + it_behaves_like 'validation error' + end - expect(response).to have_http_status(422) - expect(endpoint_push_subscriptions.count).to eq(0) - expect(endpoint_push_subscription).to be_nil + context 'with invalid p256dh key' do + let(:keys) do + { + p256dh: 'BEm_invalidf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=', + auth: 'eH_C8rq2raXqlcBVDa1gLg==', + } end + + it_behaves_like 'validation error' + end + + context 'with invalid base64 p256dh key' do + let(:keys) do + { + p256dh: 'not base64', + auth: 'eH_C8rq2raXqlcBVDa1gLg==', + } + end + + it_behaves_like 'validation error' end end From 3c435f9ba0d3a1a0a07722718eee26cf10ff55b6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 6 Jun 2024 01:52:46 +0200 Subject: [PATCH 307/658] Change counters to be displayed on profile timelines in web UI (#30525) --- app/javascript/mastodon/features/account_timeline/index.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/mastodon/features/account_timeline/index.jsx b/app/javascript/mastodon/features/account_timeline/index.jsx index 5ec029593d..0478f7a1a1 100644 --- a/app/javascript/mastodon/features/account_timeline/index.jsx +++ b/app/javascript/mastodon/features/account_timeline/index.jsx @@ -199,6 +199,7 @@ class AccountTimeline extends ImmutablePureComponent { emptyMessage={emptyMessage} bindToDocument={!multiColumn} timelineId='account' + withCounters /> ); From 569b7d2f25da120473937ab5719eba5ab0e314e1 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 5 Jun 2024 19:54:59 -0400 Subject: [PATCH 308/658] Clarify the purpose of separate Docker resources (#30568) --- Dockerfile | 3 +++ README.md | 4 +++- docker-compose.yml | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6d342db437..09aa8f2ddb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,8 @@ # syntax=docker/dockerfile:1.7 +# This file is designed for production server deployment, not local development work +# For a containerized local dev environment, see: https://github.com/mastodon/mastodon/blob/main/README.md#docker + # Please see https://docs.docker.com/engine/reference/builder for information about # the extended buildx capabilities used in this file. # Make sure multiarch TARGETPLATFORM is available for interpolation diff --git a/README.md b/README.md index b8ee3f5dbb..45291d6378 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,9 @@ To set up **MacOS** for native development, complete the following steps: ### Docker -For development with **Docker**, complete the following steps: +For production hosting and deployment with **Docker**, use the `Dockerfile` and +`docker-compose.yml` in the project root directory. To create a local +development environment with **Docker**, complete the following steps: - Install Docker Desktop - Run `docker compose -f .devcontainer/docker-compose.yml up -d` diff --git a/docker-compose.yml b/docker-compose.yml index e7ae95ea7a..7089b0d14f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,6 @@ +# This file is designed for production server deployment, not local development work +# For a containerized local dev environment, see: https://github.com/mastodon/mastodon/blob/main/README.md#docker + services: db: restart: always From e02d23b5499318432981b16d8968e109ebeca18c Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Thu, 6 Jun 2024 09:30:10 +0200 Subject: [PATCH 309/658] Change `read:me` scope to `profile` scope (#30357) Co-authored-by: Claire --- .../api/v1/accounts/credentials_controller.rb | 2 +- .../settings/applications_controller.rb | 2 +- app/lib/scope_transformer.rb | 3 ++ config/initializers/doorkeeper.rb | 4 +-- config/locales/doorkeeper.en.yml | 3 +- ...3195202_change_read_me_scope_to_profile.rb | 23 +++++++++++++++ db/schema.rb | 2 +- lib/tasks/tests.rake | 28 ++++++++++++++++++- spec/lib/scope_transformer_spec.rb | 6 ++++ .../api/v1/accounts/credentials_spec.rb | 4 +-- 10 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 db/post_migrate/20240603195202_change_read_me_scope_to_profile.rb diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb index e8f712457e..a378425183 100644 --- a/app/controllers/api/v1/accounts/credentials_controller.rb +++ b/app/controllers/api/v1/accounts/credentials_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Accounts::CredentialsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read, :'read:accounts', :'read:me' }, except: [:update] + before_action -> { doorkeeper_authorize! :profile, :read, :'read:accounts' }, except: [:update] before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update] before_action :require_user! diff --git a/app/controllers/settings/applications_controller.rb b/app/controllers/settings/applications_controller.rb index 6849979b11..d6573f9b49 100644 --- a/app/controllers/settings/applications_controller.rb +++ b/app/controllers/settings/applications_controller.rb @@ -13,7 +13,7 @@ class Settings::ApplicationsController < Settings::BaseController def new @application = Doorkeeper::Application.new( redirect_uri: Doorkeeper.configuration.native_redirect_uri, - scopes: 'read:me' + scopes: 'profile' ) end diff --git a/app/lib/scope_transformer.rb b/app/lib/scope_transformer.rb index adcb711f8a..7dda709229 100644 --- a/app/lib/scope_transformer.rb +++ b/app/lib/scope_transformer.rb @@ -11,6 +11,9 @@ class ScopeTransformer < Parslet::Transform @namespace = scope[:namespace]&.to_s @access = scope[:access] ? [scope[:access].to_s] : DEFAULT_ACCESS.dup @term = scope[:term]&.to_s || DEFAULT_TERM + + # # override for profile scope which is read only + @access = %w(read) if @term == 'profile' end def key diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 1e8f9ad506..83100b1cf5 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -74,7 +74,8 @@ Doorkeeper.configure do # For more information go to # https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes default_scopes :read - optional_scopes :write, + optional_scopes :profile, + :write, :'write:accounts', :'write:blocks', :'write:bookmarks', @@ -89,7 +90,6 @@ Doorkeeper.configure do :'write:reports', :'write:statuses', :read, - :'read:me', :'read:accounts', :'read:blocks', :'read:bookmarks', diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index 98776f2193..b623cc7135 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -135,6 +135,7 @@ en: media: Media attachments mutes: Mutes notifications: Notifications + profile: Your Mastodon profile push: Push notifications reports: Reports search: Search @@ -165,6 +166,7 @@ en: admin:write:reports: perform moderation actions on reports crypto: use end-to-end encryption follow: modify account relationships + profile: read only your account's profile information push: receive your push notifications read: read all your account's data read:accounts: see accounts information @@ -174,7 +176,6 @@ en: read:filters: see your filters read:follows: see your follows read:lists: see your lists - read:me: read only your account's basic information read:mutes: see your mutes read:notifications: see your notifications read:reports: see your reports diff --git a/db/post_migrate/20240603195202_change_read_me_scope_to_profile.rb b/db/post_migrate/20240603195202_change_read_me_scope_to_profile.rb new file mode 100644 index 0000000000..05e5984c48 --- /dev/null +++ b/db/post_migrate/20240603195202_change_read_me_scope_to_profile.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class ChangeReadMeScopeToProfile < ActiveRecord::Migration[7.1] + def up + replace_scopes('read:me', 'profile') + end + + def down + replace_scopes('profile', 'read:me') + end + + private + + def replace_scopes(old_scope, new_scope) + Doorkeeper::Application.where("scopes LIKE '%#{old_scope}%'").in_batches do |applications| + applications.update_all("scopes = replace(scopes, '#{old_scope}', '#{new_scope}')") + end + + Doorkeeper::AccessToken.where("scopes LIKE '%#{old_scope}%'").in_batches do |access_tokens| + access_tokens.update_all("scopes = replace(scopes, '#{old_scope}', '#{new_scope}')") + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 73f6b464e4..ce2951608b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_22_041528) do +ActiveRecord::Schema[7.1].define(version: 2024_06_03_195202) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index c8e0312bbd..c8e4dc31cd 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -130,11 +130,20 @@ namespace :tests do # This is checking the attribute rather than the method, to avoid the legacy fallback # and ensure the data has been migrated unless Account.find_local('qcuser').user[:otp_secret] == 'anotpsecretthatshouldbeencrypted' - puts "DEBUG: #{Account.find_local('qcuser').user.inspect}" puts 'OTP secret for user not preserved as expected' exit(1) end + unless Doorkeeper::Application.find(2)[:scopes] == 'write:accounts profile' + puts 'Application OAuth scopes not rewritten as expected' + exit(1) + end + + unless Doorkeeper::Application.find(2).access_tokens.first[:scopes] == 'write:accounts profile' + puts 'OAuth access token scopes not rewritten as expected' + exit(1) + end + puts 'No errors found. Database state is consistent with a successful migration process.' end @@ -152,6 +161,23 @@ namespace :tests do VALUES (1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now()), (1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now()); + + /* Doorkeeper records + While the `read:me` scope was technically not valid in 3.3.0, + it is still useful for the purposes of testing the `ChangeReadMeScopeToProfile` + migration. + */ + + INSERT INTO "oauth_applications" + (id, name, uid, secret, redirect_uri, scopes, created_at, updated_at) + VALUES + (2, 'foo', 'foo', 'foo', 'https://example.com/#foo', 'write:accounts read:me', now(), now()), + (3, 'bar', 'bar', 'bar', 'https://example.com/#bar', 'read:me', now(), now()); + + INSERT INTO "oauth_access_tokens" + (token, application_id, scopes, resource_owner_id, created_at) + VALUES + ('secret', 2, 'write:accounts read:me', 4, now()); SQL end diff --git a/spec/lib/scope_transformer_spec.rb b/spec/lib/scope_transformer_spec.rb index 8a9c7cf967..7bc226e94f 100644 --- a/spec/lib/scope_transformer_spec.rb +++ b/spec/lib/scope_transformer_spec.rb @@ -20,6 +20,12 @@ describe ScopeTransformer do end end + context 'with scope "profile"' do + let(:input) { 'profile' } + + it_behaves_like 'a scope', nil, 'profile', 'read' + end + context 'with scope "read"' do let(:input) { 'read' } diff --git a/spec/requests/api/v1/accounts/credentials_spec.rb b/spec/requests/api/v1/accounts/credentials_spec.rb index 8ae9c78a0e..a3f552cada 100644 --- a/spec/requests/api/v1/accounts/credentials_spec.rb +++ b/spec/requests/api/v1/accounts/credentials_spec.rb @@ -29,8 +29,8 @@ RSpec.describe 'credentials API' do }) end - describe 'allows the read:me scope' do - let(:scopes) { 'read:me' } + describe 'allows the profile scope' do + let(:scopes) { 'profile' } it 'returns the response successfully' do subject From 2fdd782f21a0d07b5c658c0e0f467c5b5622988a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 03:50:15 -0400 Subject: [PATCH 310/658] Fix empty `aria-hidden` attribute value in logo resources area (#30570) --- app/views/layouts/application.html.haml | 2 +- app/views/layouts/embedded.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 5957d1dbf5..ec6caa33ad 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -43,6 +43,6 @@ %body{ class: body_classes } = content_for?(:content) ? yield(:content) : yield - .logo-resources{ 'tabindex' => '-1', 'inert' => true, 'aria-hidden' => true } + .logo-resources{ 'tabindex' => '-1', 'inert' => true, 'aria-hidden' => 'true' } = inline_svg_tag 'logo-symbol-icon.svg' = inline_svg_tag 'logo-symbol-wordmark.svg' diff --git a/app/views/layouts/embedded.html.haml b/app/views/layouts/embedded.html.haml index c633fa9e08..f912b3fafd 100644 --- a/app/views/layouts/embedded.html.haml +++ b/app/views/layouts/embedded.html.haml @@ -20,5 +20,5 @@ %body.embed = yield - .logo-resources{ 'tabindex' => '-1', 'inert' => true, 'aria-hidden' => true } + .logo-resources{ 'tabindex' => '-1', 'inert' => true, 'aria-hidden' => 'true' } = inline_svg_tag 'logo-symbol-icon.svg' From d72714e5ce5a7146665ad833f760dba82ad7a0cd Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 03:50:31 -0400 Subject: [PATCH 311/658] Remove deprecated version value from `.devcontainer/docker-compose.yml` (#30567) --- .devcontainer/docker-compose.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 5d9917b399..85f9eb22cc 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3' - services: app: working_dir: /workspaces/mastodon/ From a2505e861150abda0e692ffe86178393d701bc93 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 6 Jun 2024 10:43:04 +0200 Subject: [PATCH 312/658] Add timeline of public posts about a trending link to REST API (#30381) --- .../api/v1/timelines/link_controller.rb | 52 +++++++ app/models/link_feed.rb | 35 +++++ config/routes/api.rb | 1 + spec/requests/api/v1/timelines/link_spec.rb | 131 ++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 app/controllers/api/v1/timelines/link_controller.rb create mode 100644 app/models/link_feed.rb create mode 100644 spec/requests/api/v1/timelines/link_spec.rb diff --git a/app/controllers/api/v1/timelines/link_controller.rb b/app/controllers/api/v1/timelines/link_controller.rb new file mode 100644 index 0000000000..af962c430f --- /dev/null +++ b/app/controllers/api/v1/timelines/link_controller.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +class Api::V1::Timelines::LinkController < Api::V1::Timelines::BaseController + before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: :show, if: :require_auth? + before_action :set_preview_card + before_action :set_statuses + + PERMITTED_PARAMS = %i( + url + limit + ).freeze + + def show + cache_if_unauthenticated! + render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) + end + + private + + def require_auth? + !Setting.timeline_preview + end + + def set_preview_card + @preview_card = PreviewCard.joins(:trend).merge(PreviewCardTrend.allowed).find_by!(url: params[:url]) + end + + def set_statuses + @statuses = @preview_card.nil? ? [] : preload_collection(link_timeline_statuses, Status) + end + + def link_timeline_statuses + link_feed.get( + limit_param(DEFAULT_STATUSES_LIMIT), + params[:max_id], + params[:since_id], + params[:min_id] + ) + end + + def link_feed + LinkFeed.new(@preview_card, current_account) + end + + def next_path + api_v1_timelines_link_url next_path_params + end + + def prev_path + api_v1_timelines_link_url prev_path_params + end +end diff --git a/app/models/link_feed.rb b/app/models/link_feed.rb new file mode 100644 index 0000000000..32efb331b6 --- /dev/null +++ b/app/models/link_feed.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +class LinkFeed < PublicFeed + # @param [PreviewCard] preview_card + # @param [Account] account + # @param [Hash] options + def initialize(preview_card, account, options = {}) + @preview_card = preview_card + super(account, options) + end + + # @param [Integer] limit + # @param [Integer] max_id + # @param [Integer] since_id + # @param [Integer] min_id + # @return [Array] + def get(limit, max_id = nil, since_id = nil, min_id = nil) + scope = public_scope + + scope.merge!(discoverable) + scope.merge!(attached_to_preview_card) + + scope.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id) + end + + private + + def attached_to_preview_card + Status.joins(:preview_cards_status).where(preview_cards_status: { preview_card_id: @preview_card.id }) + end + + def discoverable + Account.discoverable + end +end diff --git a/config/routes/api.rb b/config/routes/api.rb index 135a19a0a7..3eb4bb4b4d 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -39,6 +39,7 @@ namespace :api, format: false do namespace :timelines do resource :home, only: :show, controller: :home resource :public, only: :show, controller: :public + resource :link, only: :show, controller: :link resources :tag, only: :show resources :list, only: :show end diff --git a/spec/requests/api/v1/timelines/link_spec.rb b/spec/requests/api/v1/timelines/link_spec.rb new file mode 100644 index 0000000000..a219c9bcdd --- /dev/null +++ b/spec/requests/api/v1/timelines/link_spec.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Link' do + let(:user) { Fabricate(:user) } + let(:scopes) { 'read:statuses' } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + shared_examples 'a successful request to the link timeline' do + it 'returns the expected statuses successfully', :aggregate_failures do + subject + + expect(response).to have_http_status(200) + expect(body_as_json.pluck(:id)).to match_array(expected_statuses.map { |status| status.id.to_s }) + end + end + + describe 'GET /api/v1/timelines/link' do + subject do + get '/api/v1/timelines/link', headers: headers, params: params + end + + let(:url) { 'https://example.com/' } + let(:private_status) { Fabricate(:status, visibility: :private) } + let(:undiscoverable_status) { Fabricate(:status, account: Fabricate.build(:account, domain: nil, discoverable: false)) } + let(:local_status) { Fabricate(:status, account: Fabricate.build(:account, domain: nil, discoverable: true)) } + let(:remote_status) { Fabricate(:status, account: Fabricate.build(:account, domain: 'example.com', discoverable: true)) } + let(:params) { { url: url } } + let(:expected_statuses) { [local_status, remote_status] } + let(:preview_card) { Fabricate(:preview_card, url: url) } + + before do + if preview_card.present? + preview_card.create_trend!(allowed: true) + + [private_status, undiscoverable_status, remote_status, local_status].each do |status| + PreviewCardsStatus.create(status: status, preview_card: preview_card, url: url) + end + end + end + + context 'when there is no preview card' do + let(:preview_card) { nil } + + it 'returns http not found' do + subject + + expect(response).to have_http_status(404) + end + end + + context 'when preview card is not trending' do + before do + preview_card.trend.destroy! + end + + it 'returns http not found' do + subject + + expect(response).to have_http_status(404) + end + end + + context 'when preview card is trending but not approved' do + before do + preview_card.trend.update(allowed: false) + end + + it 'returns http not found' do + subject + + expect(response).to have_http_status(404) + end + end + + context 'when the instance does not allow public preview' do + before do + Form::AdminSettings.new(timeline_preview: false).save + end + + context 'when the user is not authenticated' do + let(:headers) { {} } + + it 'returns http unauthorized' do + subject + + expect(response).to have_http_status(401) + end + end + + context 'when the user is authenticated' do + it_behaves_like 'a successful request to the link timeline' + end + end + + context 'when the instance allows public preview' do + context 'with an authorized user' do + it_behaves_like 'a successful request to the link timeline' + end + + context 'with an anonymous user' do + let(:headers) { {} } + + it_behaves_like 'a successful request to the link timeline' + end + + context 'with limit param' do + let(:params) { { limit: 1, url: url } } + + it 'returns only the requested number of statuses', :aggregate_failures do + subject + + expect(response).to have_http_status(200) + expect(body_as_json.size).to eq(params[:limit]) + end + + it 'sets the correct pagination headers', :aggregate_failures do + subject + + expect(response) + .to include_pagination_headers( + prev: api_v1_timelines_link_url(limit: params[:limit], url: url, min_id: local_status.id), + next: api_v1_timelines_link_url(limit: params[:limit], url: url, max_id: local_status.id) + ) + end + end + end + end +end From 2f0a34ac00f2d3cc561cd4fe3edbcf2bd62c35a8 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 04:49:31 -0400 Subject: [PATCH 313/658] Run as root in devcontainer from vscode (#30574) --- .devcontainer/devcontainer.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fa8d6542c1..2c53be9c77 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -23,6 +23,8 @@ } }, + "remoteUser": "root", + "otherPortsAttributes": { "onAutoForward": "silent" }, From a729104a4159106f959bcc9b3ab438d2876ce9a5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 10:53:28 +0200 Subject: [PATCH 314/658] New Crowdin Translations (automated) (#30575) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/sk.json | 2 ++ config/locales/activerecord.ia.yml | 2 +- config/locales/devise.ia.yml | 38 ++++++++++++------------- config/locales/devise.sv.yml | 6 ++-- config/locales/doorkeeper.ia.yml | 36 +++++++++++------------ config/locales/ia.yml | 2 +- config/locales/simple_form.ia.yml | 6 ++-- 7 files changed, 47 insertions(+), 45 deletions(-) diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index c583b58220..9b5be21f9d 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -391,6 +391,7 @@ "limited_account_hint.action": "Aj tak zobraziť profil", "limited_account_hint.title": "Tento profil bol skrytý správcami servera {domain}.", "link_preview.author": "Autor: {name}", + "link_preview.more_from_author": "Viac od {name}", "lists.account.add": "Pridať do zoznamu", "lists.account.remove": "Odstrániť zo zoznamu", "lists.delete": "Vymazať zoznam", @@ -411,6 +412,7 @@ "moved_to_account_banner.text": "Váš účet {disabledAccount} je momentálne deaktivovaný, pretože ste sa presunuli na {movedToAccount}.", "mute_modal.hide_from_notifications": "Ukryť z upozornení", "mute_modal.hide_options": "Skryť možnosti", + "mute_modal.indefinite": "Pokiaľ ich neodtíšim", "mute_modal.show_options": "Zobraziť možnosti", "mute_modal.title": "Stíšiť užívateľa?", "navigation_bar.about": "O tomto serveri", diff --git a/config/locales/activerecord.ia.yml b/config/locales/activerecord.ia.yml index b1dd90bc36..bf1fbc67ef 100644 --- a/config/locales/activerecord.ia.yml +++ b/config/locales/activerecord.ia.yml @@ -19,7 +19,7 @@ ia: account: attributes: username: - invalid: debe continer solmente litteras, numeros e tractos de sublineamento + invalid: debe continer solmente litteras, numeros e lineettas basse reserved: es reservate admin/webhook: attributes: diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index e6ae6d4afb..8e073c9efb 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -3,8 +3,8 @@ ia: devise: confirmations: confirmed: Tu conto de e-mail ha essite confirmate con successo. - send_instructions: Tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe. - send_paranoid_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe. + send_instructions: Tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor consulta tu dossier de spam si tu non lo recipe. + send_paranoid_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un e-mail con instructiones pro confirmar tu adresse de e-mail in poc minutas. Per favor consulta tu dossier de spam si tu non lo recipe. failure: already_authenticated: Tu ha jam aperite session. inactive: Tu conto non es ancora activate. @@ -27,7 +27,7 @@ ia: subject: 'Mastodon: Instructiones de confirmation pro %{instance}' title: Verificar adresse de e-mail email_changed: - explanation: 'Le adresse de e-mail pro tu conto essera cambiate a:' + explanation: 'Le adresse de e-mail pro tu conto se cambia in:' extra: Si tu non ha cambiate de adresse de e-mail, es probabile que alcuno ha ganiate le accesso a tu conto. Per favor cambia immediatemente tu contrasigno o contacta le administrator del servitor si tu non pote acceder a tu conto. subject: 'Mastodon: E-mail cambiate' title: Nove adresse de e-mail @@ -37,8 +37,8 @@ ia: subject: 'Mastodon: Contrasigno cambiate' title: Contrasigno cambiate reconfirmation_instructions: - explanation: Confirma le nove adresse pro cambiar tu email. - extra: Si non es tu qui ha initiate iste cambiamento, per favor ignora iste e-mail. Le adresse de e-mail pro le conto de Mastodon non cambiara usque tu accede al ligamine hic supra. + explanation: Confirma le nove adresse pro cambiar tu adresse de e-mail. + extra: Si non es tu qui ha initiate iste cambiamento, per favor ignora iste e-mail. Le adresse de e-mail pro le conto de Mastodon non cambiara usque tu accede al ligamine supra. subject: 'Mastodon: Confirmar e-mail pro %{instance}' title: Verificar adresse de e-mail reset_password_instructions: @@ -49,19 +49,19 @@ ia: title: Reinitialisar contrasigno two_factor_disabled: explanation: Ora es possibile aperir session con solmente le adresse de e-mail e contrasigno. - subject: 'Mastodon: Authentication bifactorial disactivate' - subtitle: Le authentication bifactorial ha essite disactivate pro tu conto. + subject: 'Mastodon: Authentication a duo factores disactivate' + subtitle: Le authentication a duo factores ha essite disactivate pro tu conto. title: A2F disactivate two_factor_enabled: explanation: Pro le apertura de session essera necessari un token generate per le application TOTP accopulate. - subject: 'Mastodon: Authentication bifactorial activate' - subtitle: Le authentication bifactorial ha essite activate pro tu conto. + subject: 'Mastodon: Authentication a duo factores activate' + subtitle: Le authentication a duo factores ha essite activate pro tu conto. title: A2F activate two_factor_recovery_codes_changed: explanation: Le ancian codices de recuperation ha essite invalidate e nove codices ha essite generate. - subject: 'Mastodon: Codices de recuperation regenerate' + subject: 'Mastodon: Codices de recuperation A2F regenerate' subtitle: Le ancian codices de recuperation ha essite invalidate e nove codices ha essite generate. - title: Codices de recuperation cambiate + title: Codices de recuperation A2F cambiate unlock_instructions: subject: 'Mastodon: Instructiones pro disblocar' webauthn_credential: @@ -84,11 +84,11 @@ ia: subject: 'Mastodon: authentication de clave de securitate activate' title: Claves de securitate activate omniauth_callbacks: - failure: Impossibile authenticar te ab %{kind} perque “%{reason}”. - success: Authenticate con successo ab conto %{kind}. + failure: Non poteva authenticar te desde %{kind} perque “%{reason}”. + success: Authenticate correctemente desde le conto %{kind}. passwords: - no_token: Tu non pote acceder iste pagina sin venir ab un email de redefinition de contrasigno. Si tu veni ab un email de redefinition de contrasigno, verifica que tu usava le integre URL fornite. - send_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un ligamine de recuperation de contrasigno in tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe. + no_token: Non es possibile acceder a iste pagina sin venir de un e-mail de redefinition de contrasigno. Si tu veni de un e-mail de redefinition de contrasigno, per favor assecura te de haber usate le URL complete fornite. + send_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un ligamine de recuperation de contrasigno a tu adresse de e-mail in poc minutas. Per favor consulta tu dossier de spam si tu non lo recipe. send_paranoid_instructions: Si tu adresse de e-mail existe in nostre base de datos, tu recipera un ligamine de recuperation de contrasigno in tu adresse de e-mail in poc minutas. Per favor verifica tu dossier de spam si tu non lo recipe. updated: Tu contrasigno ha essite cambiate. Tu ha ora aperite session. updated_not_active: Tu contrasigno ha essite cambiate. @@ -98,17 +98,17 @@ ia: signed_up_but_inactive: Tu te ha inscribite con successo. Nonobstante, nos non poteva aperir tu session perque tu conto non es ancora activate. signed_up_but_locked: Tu te ha inscribite con successo. Nonobstante, nos non poteva aperir tu session perque tu conto es serrate. signed_up_but_pending: Un message con un ligamine de confirmation ha essite inviate a tu adresse de email. Post que tu clicca sur le ligamine, nos revidera tu demanda. Tu essera notificate si illo es approbate. - signed_up_but_unconfirmed: Un message con un ligamine de confirmation ha essite inviate a tu adresse de e-mail. Per favor seque le ligamine pro activar tu conto. Verifica tu dossier de spam si tu non recipe iste e-mail. - update_needs_confirmation: Tu ha actualisate tu conto con successo, ma nos debe verificar tu nove adresse de e-mail. Accede a tu e-mail e seque le ligamine de confirmation pro confirmar tu nove adresse de e-mail. Verifica tu dossier de spam si tu non recipe iste e-mail. + signed_up_but_unconfirmed: Un message con un ligamine de confirmation ha essite inviate a tu adresse de e-mail. Per favor seque le ligamine pro activar tu conto. Consulta tu dossier de spam si tu non recipe iste e-mail. + update_needs_confirmation: Tu ha actualisate tu conto con successo, ma nos debe verificar tu nove adresse de e-mail. Accede a tu e-mail e seque le ligamine de confirmation pro confirmar tu nove adresse de e-mail. Consulta tu dossier de spam si tu non recipe iste e-mail. updated: Tu conto ha essite actualisate con successo. sessions: already_signed_out: Session claudite con successo. signed_in: Session aperite con successo. signed_out: Session claudite con successo. unlocks: - send_instructions: Tu recipera un e-mail con instructiones explicante como disserrar tu conto in alcun minutas. Verifica tu dossier de spam si tu non recipe iste e-mail. + send_instructions: Tu recipera un e-mail con instructiones explicante como disserrar tu conto in alcun minutas. Consulta tu dossier de spam si tu non recipe iste e-mail. send_paranoid_instructions: Si tu conto existe, tu recipera un email con instructiones explicante como disserrar lo in alcun minutas. Verifica tu dossier de spam si tu non recipe iste e-mail. - unlocked: Tu conto ha essite disserrate con successo. Aperi session pro continuar. + unlocked: Tu conto ha essite disserrate con successo. Per favor aperi session pro continuar. errors: messages: already_confirmed: jam esseva confirmate, tenta aperir session diff --git a/config/locales/devise.sv.yml b/config/locales/devise.sv.yml index 27d424f618..1e14a7de52 100644 --- a/config/locales/devise.sv.yml +++ b/config/locales/devise.sv.yml @@ -30,14 +30,14 @@ sv: explanation: 'E-postadressen för ditt konto ändras till:' extra: Om du inte ändrade din e-post är det troligt att någon har fått tillgång till ditt konto. Vänligen ändra ditt lösenord omedelbart eller kontakta serveradministratören om du är utelåst från ditt konto. subject: 'Mastodon: e-post ändrad' - title: Ny e-post adress + title: Ny e-postadress password_change: explanation: Lösenordet för ditt konto har ändrats. extra: Om du inte ändrade ditt lösenord är det troligt att någon har fått tillgång till ditt konto. Vänligen ändra ditt lösenord omedelbart eller kontakta serveradministratören om du är utelåst från ditt konto. subject: 'Mastodon: Lösenordet har ändrats' title: Lösenordet har ändrats reconfirmation_instructions: - explanation: Bekräfta den nya adressen för att ändra din e-post adress. + explanation: Bekräfta den nya adressen för att ändra din e-postadress. extra: Om den här ändringen inte initierades av dig kan du ignorera det här e-postmeddelandet. E-postadressen för Mastodon-kontot ändras inte förrän du klickar på länken ovan. subject: 'Mastodon: Bekräfta e-post för %{instance}' title: Verifiera e-postadress @@ -63,7 +63,7 @@ sv: subtitle: De tidigare återhämtningskoderna har ogiltigförklarats och nya har skapats. title: 2FA-återställningskoder ändrades unlock_instructions: - subject: 'Mastodon: Lås upp instruktioner' + subject: 'Mastodon: Instruktioner för upplåsning' webauthn_credential: added: explanation: Följande säkerhetsnyckel har lagts till i ditt konto diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index 82a1b4b140..40109a311c 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -61,7 +61,7 @@ ia: title: Un error ha occurrite new: prompt_html: "%{client_name} vole haber le permission de acceder a tu conto. Illo es un application tertie. Si tu non confide in illo, alora tu non deberea autorisar lo." - review_permissions: Revisionar le permissos + review_permissions: Revider permissiones title: Autorisation necessari show: title: Copia iste codice de autorisation e colla lo in le application. @@ -148,34 +148,34 @@ ia: title: Autorisation OAuth necessari scopes: admin:read: leger tote le datos in le servitor - admin:read:accounts: leger information sensibile de tote le contos - admin:read:canonical_email_blocks: leger datos sensibile de tote le blocadas de email canonic + admin:read:accounts: leger informationes sensibile de tote le contos + admin:read:canonical_email_blocks: leger informationes sensibile de tote le blocadas de e-mail canonic admin:read:domain_allows: leger informationes sensibile de tote le dominios permittite admin:read:domain_blocks: leger informationes sensibile de tote le blocadas de dominio - admin:read:email_domain_blocks: leger informationes sensibile de tote le blocadas de dominio email - admin:read:ip_blocks: leger informationes sensibile de tote le blocadas de IP - admin:read:reports: leger information sensibile de tote le reportos e contos reportate + admin:read:email_domain_blocks: leger informationes sensibile de tote le blocadas de dominio de e-mail + admin:read:ip_blocks: leger informationes sensibile de tote le blocadas de adresses IP + admin:read:reports: leger informationes sensibile de tote le reportos e contos reportate admin:write: modificar tote le datos in le servitor - admin:write:accounts: exequer action de moderation sur contos - admin:write:canonical_email_blocks: exequer actiones de moderation sur blocadas de email canonic + admin:write:accounts: exequer actiones de moderation sur contos + admin:write:canonical_email_blocks: exequer actiones de moderation sur blocadas de e-mail canonic admin:write:domain_allows: exequer actiones de moderation sur dominios permittite admin:write:domain_blocks: exequer actiones de moderation sur blocadas de dominio - admin:write:email_domain_blocks: exequer actiones de moderation sur blocadas de dominio email - admin:write:ip_blocks: exequer actiones de moderation sur blocadas de IP - admin:write:reports: exequer action de moderation sur reportos - crypto: usar cryptation de extremo-a-extremo - follow: modificar relationes del contos + admin:write:email_domain_blocks: exequer actiones de moderation sur blocadas de dominio de e-mail + admin:write:ip_blocks: exequer actiones de moderation sur blocadas de adresses IP + admin:write:reports: exequer actiones de moderation sur reportos + crypto: usar cryptation de puncta a puncta + follow: modificar relationes inter contos push: reciper tu notificationes push read: leger tote le datos de tu conto - read:accounts: vider informationes de conto + read:accounts: vider informationes de contos read:blocks: vider tu blocadas read:bookmarks: vider tu marcapaginas - read:favourites: vider tu favoritos + read:favourites: vider tu favorites read:filters: vider tu filtros - read:follows: vider tu sequites + read:follows: vider qui tu seque read:lists: vider tu listas read:me: leger solmente le information basic de tu conto - read:mutes: vider tu silentiates + read:mutes: vider qui tu silentia read:notifications: vider tu notificationes read:reports: vider tu reportos read:search: cercar in tu nomine @@ -189,7 +189,7 @@ ia: write:filters: crear filtros write:follows: sequer personas write:lists: crear listas - write:media: incargar files de medios + write:media: incargar files multimedial write:mutes: silentiar personas e conversationes write:notifications: rader tu notificationes write:reports: reportar altere personas diff --git a/config/locales/ia.yml b/config/locales/ia.yml index cadc465c55..b7f4ecf85d 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -1102,7 +1102,7 @@ ia: security: Securitate set_new_password: Definir un nove contrasigno setup: - email_below_hint_html: Consulta tu dossier de spam, o requesta un altere. Tu pote corriger tu adresse de e-mail si illo es errate. + email_below_hint_html: Consulta tu dossier de spam, o requesta un altere ligamine de confirmation. Tu pote corriger tu adresse de e-mail si illo es errate. email_settings_hint_html: Clicca sur le ligamine que nos te ha inviate pro verificar %{email}. Nos te attendera hic. link_not_received: Necun ligamine recipite? new_confirmation_instructions_sent: Tu recipera un nove e-mail con le ligamine de confirmation in poc minutas! diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index 7e364889dd..2d0af3001e 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -8,7 +8,7 @@ ia: fields: Tu pagina principal, pronomines, etate, tote lo que tu vole. indexable: Tu messages public pote apparer in le resultatos de recerca sur Mastodon. Le personas qui ha interagite con tu messages pote cercar los in omne caso. note: 'Tu pote @mentionar altere personas o #hashtags.' - show_collections: Le personas potera percurrer tu sequites e sequitores. Le personas que tu seque videra que tu les seque in omne caso. + show_collections: Le gente potera percurrer le listas de personas que tu seque e qui te seque. Le personas que tu seque videra que tu les seque in omne caso. unlocked: Le personas potera sequer te sin requestar approbation. Dismarca si tu vole revider le requestas de sequimento e seliger si acceptar o rejectar nove sequitores. account_alias: acct: Specifica le nomine_de_usator@dominio del conto desde le qual tu vole migrar @@ -38,7 +38,7 @@ ia: appeal: text: Tu pote solo appellar contra un sanction un vice defaults: - autofollow: Illes qui se inscribe per le invitation automaticamente devenira tu sequaces + autofollow: Le personas qui se inscribe per medio del invitation te sequera automaticamente avatar: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px bot: Signala a alteres que le conto principalmente exeque actiones automatisate e poterea non esser surveliate context: Un o plure contextos ubi le filtro deberea applicar se @@ -269,7 +269,7 @@ ia: trends: Activar tendentias trends_as_landing_page: Usar tendentias como pagina de destination interactions: - must_be_follower: Blocar notificationes de non-sequaces + must_be_follower: Blocar notificationes de personas qui non te seque must_be_following: Blocar notificationes de gente que tu non sequer must_be_following_dm: Blocar messages directe de gente que tu non seque invite: From cd4b00810d49bb95b6421c84d48a6e075a18486c Mon Sep 17 00:00:00 2001 From: Fabio Leandro Janiszevski Date: Thu, 6 Jun 2024 06:00:09 -0300 Subject: [PATCH 315/658] Clear the docker setup - Deprecate post-create.sh and use bin/setup (#30502) --- .devcontainer/codespaces/devcontainer.json | 2 +- .devcontainer/devcontainer.json | 2 +- .devcontainer/post-create.sh | 27 ---------------------- README.md | 2 +- 4 files changed, 3 insertions(+), 30 deletions(-) delete mode 100755 .devcontainer/post-create.sh diff --git a/.devcontainer/codespaces/devcontainer.json b/.devcontainer/codespaces/devcontainer.json index ca9156fdaa..6736734e60 100644 --- a/.devcontainer/codespaces/devcontainer.json +++ b/.devcontainer/codespaces/devcontainer.json @@ -37,7 +37,7 @@ }, "onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}", - "postCreateCommand": ".devcontainer/post-create.sh", + "postCreateCommand": "bin/setup", "waitFor": "postCreateCommand", "customizations": { diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2c53be9c77..4a9cf11cc2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -30,7 +30,7 @@ }, "onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}", - "postCreateCommand": ".devcontainer/post-create.sh", + "postCreateCommand": "bin/setup", "waitFor": "postCreateCommand", "customizations": { diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh deleted file mode 100755 index 82a2ccbb6c..0000000000 --- a/.devcontainer/post-create.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -set -e # Fail the whole script on first error - -# Fetch Ruby gem dependencies -bundle config path 'vendor/bundle' -bundle config with 'development test' -bundle install - -# Make Gemfile.lock pristine again -git checkout -- Gemfile.lock - -# Fetch Javascript dependencies -corepack prepare -yarn install --immutable - -# [re]create, migrate, and seed the test database -RAILS_ENV=test ./bin/rails db:setup - -# [re]create, migrate, and seed the development database -RAILS_ENV=development ./bin/rails db:setup - -# Precompile assets for development -RAILS_ENV=development ./bin/rails assets:precompile - -# Precompile assets for test -RAILS_ENV=test ./bin/rails assets:precompile diff --git a/README.md b/README.md index 45291d6378..3773b647fe 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ development environment with **Docker**, complete the following steps: - Install Docker Desktop - Run `docker compose -f .devcontainer/docker-compose.yml up -d` -- Run `docker compose -f .devcontainer/docker-compose.yml exec app .devcontainer/post-create.sh` +- Run `docker compose -f .devcontainer/docker-compose.yml exec app bin/setup` - Finally, run `docker compose -f .devcontainer/docker-compose.yml exec app bin/dev` If you are using an IDE with [support for the Development Container specification](https://containers.dev/supporting), it will run the above `docker compose` commands automatically. For **Visual Studio Code** this requires the [Dev Container extension](https://containers.dev/supporting#dev-containers). From 5652ca613582df03e5b838626078981414f3b897 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:27:54 +0200 Subject: [PATCH 316/658] fix(deps): update babel monorepo to v7.24.7 (#30561) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 1290 +++++++++++++++++++++++++++-------------------------- 1 file changed, 649 insertions(+), 641 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7c36984cde..dcc17d6599 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,128 +42,129 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/code-frame@npm:7.24.6" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/code-frame@npm:7.24.7" dependencies: - "@babel/highlight": "npm:^7.24.6" + "@babel/highlight": "npm:^7.24.7" picocolors: "npm:^1.0.0" - checksum: 10c0/c93c6d1763530f415218c31d07359364397f19b70026abdff766164c21ed352a931cf07f3102c5fb9e04792de319e332d68bcb1f7debef601a02197f90f9ba24 + checksum: 10c0/ab0af539473a9f5aeaac7047e377cb4f4edd255a81d84a76058595f8540784cc3fbe8acf73f1e073981104562490aabfb23008cd66dc677a456a4ed5390fdde6 languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/compat-data@npm:7.24.6" - checksum: 10c0/f50abbd4008eb2a5d12139c578809cebbeaeb8e660fb12d546eb2e7c2108ae1836ab8339184a5f5ce0e95bf81bb91e18edce86b387c59db937b01693ec0bc774 +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/compat-data@npm:7.24.7" + checksum: 10c0/dcd93a5632b04536498fbe2be5af1057f635fd7f7090483d8e797878559037e5130b26862ceb359acbae93ed27e076d395ddb4663db6b28a665756ffd02d324f languageName: node linkType: hard "@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1, @babel/core@npm:^7.24.4": - version: 7.24.6 - resolution: "@babel/core@npm:7.24.6" + version: 7.24.7 + resolution: "@babel/core@npm:7.24.7" dependencies: "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.24.6" - "@babel/generator": "npm:^7.24.6" - "@babel/helper-compilation-targets": "npm:^7.24.6" - "@babel/helper-module-transforms": "npm:^7.24.6" - "@babel/helpers": "npm:^7.24.6" - "@babel/parser": "npm:^7.24.6" - "@babel/template": "npm:^7.24.6" - "@babel/traverse": "npm:^7.24.6" - "@babel/types": "npm:^7.24.6" + "@babel/code-frame": "npm:^7.24.7" + "@babel/generator": "npm:^7.24.7" + "@babel/helper-compilation-targets": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.24.7" + "@babel/helpers": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.7" + "@babel/template": "npm:^7.24.7" + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10c0/e0762a8daef7f417494d555929418cfacd6848c7fc3310ec00e6dd8cecac20b7f590e760bfc9365d2af07874a3f5599832f9c9ff7f1a9d126a168f77ba67945a + checksum: 10c0/4004ba454d3c20a46ea66264e06c15b82e9f6bdc35f88819907d24620da70dbf896abac1cb4cc4b6bb8642969e45f4d808497c9054a1388a386cf8c12e9b9e0d languageName: node linkType: hard -"@babel/generator@npm:^7.24.6, @babel/generator@npm:^7.7.2": - version: 7.24.6 - resolution: "@babel/generator@npm:7.24.6" +"@babel/generator@npm:^7.24.7, @babel/generator@npm:^7.7.2": + version: 7.24.7 + resolution: "@babel/generator@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" + "@babel/types": "npm:^7.24.7" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^2.5.1" - checksum: 10c0/8d71a17b386536582354afba53cc784396458a88cc9f05f0c6de0ec99475f6f539943b3566b2e733820c4928236952473831765e483c25d68cc007a6e604d782 + checksum: 10c0/06b1f3350baf527a3309e50ffd7065f7aee04dd06e1e7db794ddfde7fe9d81f28df64edd587173f8f9295496a7ddb74b9a185d4bf4de7bb619e6d4ec45c8fd35 languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-annotate-as-pure@npm:7.24.6" +"@babel/helper-annotate-as-pure@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/3fe446e3bd37e5e32152279c84ace4e83815e5b88b9e09a82a83974a0bb22e941d89db26b23aaab4c9eb0f9713772c2f6163feffc1bcb055c4cdb6b67e5dc82f + "@babel/types": "npm:^7.24.7" + checksum: 10c0/4679f7df4dffd5b3e26083ae65228116c3da34c3fff2c11ae11b259a61baec440f51e30fd236f7a0435b9d471acd93d0bc5a95df8213cbf02b1e083503d81b9a languageName: node linkType: hard -"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.24.6" +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/d468ba492163bdcf5b6c53248edcf0aaed6194c0f7bdebef4f29ef626e5b03e9fcc7ed737445eb80a961ec6e687c330e1c5242d8a724efb0af002141f3b3e66c + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/0ed84abf848c79fb1cd4c1ddac12c771d32c1904d87fc3087f33cfdeb0c2e0db4e7892b74b407d9d8d0c000044f3645a7391a781f788da8410c290bb123a1f13 languageName: node linkType: hard -"@babel/helper-builder-react-jsx@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-builder-react-jsx@npm:7.24.6" +"@babel/helper-builder-react-jsx@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-builder-react-jsx@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" - "@babel/types": "npm:^7.24.6" - checksum: 10c0/93b0500d00f214bc2f7f142ebfa0a634872cadd446bd767f7d58b26ae1b46e1f262b0fe80a9151691463611a3148a69ad28f930295d976bf8ced32c79449a3ce + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/c95c8856c67c57060461f39b669707b2dca3501149bcc54b7c3e49c95069afce52179fc7c2bd809981acfbfdf0860ef1035dd7512cdba46c83bdb1ad6f6dc53f languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-compilation-targets@npm:7.24.6" +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-compilation-targets@npm:7.24.7" dependencies: - "@babel/compat-data": "npm:^7.24.6" - "@babel/helper-validator-option": "npm:^7.24.6" + "@babel/compat-data": "npm:^7.24.7" + "@babel/helper-validator-option": "npm:^7.24.7" browserslist: "npm:^4.22.2" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10c0/4d41150086959f5f4d72d27bae29204192e943537ecb71df1711d1f5d8791358a44f3a5882ed3c8238ba0c874b0b55213af43767e14771765f13b8d15b262432 + checksum: 10c0/1d580a9bcacefe65e6bf02ba1dafd7ab278269fef45b5e281d8354d95c53031e019890464e7f9351898c01502dd2e633184eb0bcda49ed2ecd538675ce310f51 languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-create-class-features-plugin@npm:7.24.6" +"@babel/helper-create-class-features-plugin@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-create-class-features-plugin@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-function-name": "npm:^7.24.6" - "@babel/helper-member-expression-to-functions": "npm:^7.24.6" - "@babel/helper-optimise-call-expression": "npm:^7.24.6" - "@babel/helper-replace-supers": "npm:^7.24.6" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" - "@babel/helper-split-export-declaration": "npm:^7.24.6" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-function-name": "npm:^7.24.7" + "@babel/helper-member-expression-to-functions": "npm:^7.24.7" + "@babel/helper-optimise-call-expression": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/helper-split-export-declaration": "npm:^7.24.7" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/e6734671bc6a5f3cca4ec46e4cc70238e5a2fa063e51225c2be572f157119002af419b33ea0f846dbb1307370fe9f3aa92d199449abbea5e88e0262513c8a821 + checksum: 10c0/6b7b47d70b41c00f39f86790cff67acf2bce0289d52a7c182b28e797f4e0e6d69027e3d06eccf1d54dddc2e5dde1df663bb1932437e5f447aeb8635d8d64a6ab languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.24.6" +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" regexpu-core: "npm:^5.3.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/c6e1b07c94b3b93a3f534039da88bc67ec3156080f1959aa07d5d534e9a640de3533e7ded0516dfcbccde955e91687044e6a950852b1d3f402ac5d5001be56cf + checksum: 10c0/ed611a7eb0c71843f9cdc471eeb38767972229f9225f7aaa90d124d7ee0062cf6908fd53ee9c34f731394c429594f06049a7738a71d342e0191d4047b2fc0ac2 languageName: node linkType: hard @@ -182,242 +183,249 @@ __metadata: languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-environment-visitor@npm:7.24.6" - checksum: 10c0/fdcd18ac505ed71f40c05cc992b648a4495b0aa5310a774492a0f74d8dcf3579691102f516561a651d3de6c3a44fe64bfb3049d11c14c5857634ef1823ea409a +"@babel/helper-environment-visitor@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-environment-visitor@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + checksum: 10c0/36ece78882b5960e2d26abf13cf15ff5689bf7c325b10a2895a74a499e712de0d305f8d78bb382dd3c05cfba7e47ec98fe28aab5674243e0625cd38438dd0b2d languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-function-name@npm:7.24.6" +"@babel/helper-function-name@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-function-name@npm:7.24.7" dependencies: - "@babel/template": "npm:^7.24.6" - "@babel/types": "npm:^7.24.6" - checksum: 10c0/5ba2f8db789b3f5a2b2239300a217aa212e303cd7bfad9c8b90563807f49215e8c679e8f8f177b6aaca2038038e29bc702b83839e1f7b4896d79c44a75cac97a + "@babel/template": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/e5e41e6cf86bd0f8bf272cbb6e7c5ee0f3e9660414174435a46653efba4f2479ce03ce04abff2aa2ef9359cf057c79c06cb7b134a565ad9c0e8a50dcdc3b43c4 languageName: node linkType: hard -"@babel/helper-hoist-variables@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-hoist-variables@npm:7.24.6" +"@babel/helper-hoist-variables@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-hoist-variables@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/e10ec6b864aaa419ec4934f5fcb5d0cfcc9d0657584a1b6c3c42ada949d44ca6bffcdab433a90ada4396c747e551cca31ba0e565ea005ab3f50964e3817bf6cf + "@babel/types": "npm:^7.24.7" + checksum: 10c0/19ee37563bbd1219f9d98991ad0e9abef77803ee5945fd85aa7aa62a67c69efca9a801696a1b58dda27f211e878b3327789e6fd2a6f6c725ccefe36774b5ce95 languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-member-expression-to-functions@npm:7.24.6" +"@babel/helper-member-expression-to-functions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/7595f62978f55921b24de6ed5252fcedbffacfb8271f71e092f38724179ba554cb3a24a4764a1a3890b8a53504c2bee9c99eab81f1f365582739f566c8e28eaa + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/9638c1d33cf6aba028461ccd3db6061c76ff863ca0d5013dd9a088bf841f2f77c46956493f9da18355c16759449d23b74cc1de4da357ade5c5c34c858f840f0a languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.0.0-beta.49, @babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-module-imports@npm:7.24.6" +"@babel/helper-module-imports@npm:^7.0.0-beta.49, @babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-module-imports@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/e0db3fbfcd963d138f0792ff626f940a576fcf212d02b8fe6478dccf3421bd1c2a76f8e69c7450c049985e7b63b30be309a24eeeb6ad7c2137a31b676a095a84 + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/97c57db6c3eeaea31564286e328a9fb52b0313c5cfcc7eee4bc226aebcf0418ea5b6fe78673c0e4a774512ec6c86e309d0f326e99d2b37bfc16a25a032498af0 languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-module-transforms@npm:7.24.6" +"@babel/helper-module-transforms@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-module-transforms@npm:7.24.7" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-module-imports": "npm:^7.24.6" - "@babel/helper-simple-access": "npm:^7.24.6" - "@babel/helper-split-export-declaration": "npm:^7.24.6" - "@babel/helper-validator-identifier": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-module-imports": "npm:^7.24.7" + "@babel/helper-simple-access": "npm:^7.24.7" + "@babel/helper-split-export-declaration": "npm:^7.24.7" + "@babel/helper-validator-identifier": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/9e2e3d0ddb397b36b9e8c7d94e175a36be8cb888ef370cefef2cdfd53ae1f87d567b268bd90ed9a6c706485a8de3da19cac577657613e9cd17210b91cbdfb00b + checksum: 10c0/4f311755fcc3b4cbdb689386309cdb349cf0575a938f0b9ab5d678e1a81bbb265aa34ad93174838245f2ac7ff6d5ddbd0104638a75e4e961958ed514355687b6 languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-optimise-call-expression@npm:7.24.6" +"@babel/helper-optimise-call-expression@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/7fce2c4ce22c4ba3c2178d1ce85f34fc9bbe286af5ec153b4b6ea9bf2212390359c4a1e8a54551c4daa4688022d619668bdb8c8060cb185c0c9ad02c5247efc9 + "@babel/types": "npm:^7.24.7" + checksum: 10c0/ca6a9884705dea5c95a8b3ce132d1e3f2ae951ff74987d400d1d9c215dae9c0f9e29924d8f8e131e116533d182675bc261927be72f6a9a2968eaeeaa51eb1d0f languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.6, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.24.6 - resolution: "@babel/helper-plugin-utils@npm:7.24.6" - checksum: 10c0/636d3ce8cabc0621c1f78187e1d95f1087209921fa452f76aad06224ef5dffb3d934946f5183109920f32a4b94dd75ac91c63bc52813fee639d10cd54d49ba1f +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.24.7 + resolution: "@babel/helper-plugin-utils@npm:7.24.7" + checksum: 10c0/c3d38cd9b3520757bb4a279255cc3f956fc0ac1c193964bd0816ebd5c86e30710be8e35252227e0c9d9e0f4f56d9b5f916537f2bc588084b0988b4787a967d31 languageName: node linkType: hard -"@babel/helper-remap-async-to-generator@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-remap-async-to-generator@npm:7.24.6" +"@babel/helper-remap-async-to-generator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-remap-async-to-generator@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-wrap-function": "npm:^7.24.6" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-wrap-function": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/b379b844eba352ac9487d31867e7bb2b8a264057f1739d9161b614145ea6e60969a7a82e75e5e83089e50cf1b6559f53aa085a787942bf40706fee15a2faa33c + checksum: 10c0/4e7fa2cdcbc488e41c27066c16e562857ef3c5c2bfe70d2f1e32e9ee7546b17c3fc1c20d05bf2a7f1c291bd9e7a0a219f6a9fa387209013294be79a26fcfe64d languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-replace-supers@npm:7.24.6" +"@babel/helper-replace-supers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-replace-supers@npm:7.24.7" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-member-expression-to-functions": "npm:^7.24.6" - "@babel/helper-optimise-call-expression": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-member-expression-to-functions": "npm:^7.24.7" + "@babel/helper-optimise-call-expression": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/aaf2dfaf25360da1525ecea5979d5afed201b96f0feeed2e15f90883a97776132a720b25039e67fee10a5c537363aea5cc2a46c0f1d13fdb86d0e920244f2da7 + checksum: 10c0/0e133bb03371dee78e519c334a09c08e1493103a239d9628db0132dfaac3fc16380479ca3c590d278a9b71b624030a338c18ebbfe6d430ebb2e4653775c4b3e3 languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-simple-access@npm:7.24.6" +"@babel/helper-simple-access@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-simple-access@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/b17e404dd6c9787fc7d558aea5222471a77e29596705f0d10b4c2a58b9d71ff7eae915094204848cc1af99b771553caa69337a768b9abdd82b54a0050ba83eb9 + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/7230e419d59a85f93153415100a5faff23c133d7442c19e0cd070da1784d13cd29096ee6c5a5761065c44e8164f9f80e3a518c41a0256df39e38f7ad6744fed7 languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.6" +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/6928f698362d6082a67ee2bc73991ef6b0cc6b5f2854177389bc8f3c09296580f0ee20134dd1a29dfcb1906ad9e346fa0f7c6fcd7589ab3ff176d4f09504577f + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/e3a9b8ac9c262ac976a1bcb5fe59694db5e6f0b4f9e7bdba5c7693b8b5e28113c23bdaa60fe8d3ec32a337091b67720b2053bcb3d5655f5406536c3d0584242b languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-split-export-declaration@npm:7.24.6" +"@babel/helper-split-export-declaration@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-split-export-declaration@npm:7.24.7" dependencies: - "@babel/types": "npm:^7.24.6" - checksum: 10c0/53a5dd8691fdffc89cc7fcf5aed0ad1d8bc39796a5782a3d170dcbf249eb5c15cc8a290e8d09615711d18798ad04a7d0694ab5195d35fa651abbc1b9c885d6a8 + "@babel/types": "npm:^7.24.7" + checksum: 10c0/0254577d7086bf09b01bbde98f731d4fcf4b7c3fa9634fdb87929801307c1f6202a1352e3faa5492450fa8da4420542d44de604daf540704ff349594a78184f6 languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-string-parser@npm:7.24.6" - checksum: 10c0/95115bf676e92c4e99166395649108d97447e6cabef1fabaec8cdbc53a43f27b5df2268ff6534439d405bc1bd06685b163eb3b470455bd49f69159dada414145 +"@babel/helper-string-parser@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-string-parser@npm:7.24.7" + checksum: 10c0/47840c7004e735f3dc93939c77b099bb41a64bf3dda0cae62f60e6f74a5ff80b63e9b7cf77b5ec25a324516381fc994e1f62f922533236a8e3a6af57decb5e1e languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-validator-identifier@npm:7.24.6" - checksum: 10c0/d29d2e3fca66c31867a009014169b93f7bc21c8fc1dd7d0b9d85d7a4000670526ff2222d966febb75a6e12f9859a31d1e75b558984e28ecb69651314dd0a6fd1 +"@babel/helper-validator-identifier@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-validator-identifier@npm:7.24.7" + checksum: 10c0/87ad608694c9477814093ed5b5c080c2e06d44cb1924ae8320474a74415241223cc2a725eea2640dd783ff1e3390e5f95eede978bc540e870053152e58f1d651 languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-validator-option@npm:7.24.6" - checksum: 10c0/787268dff5cf77f3b704454b96ab7b58aa4f43b2808247e51859a103a1c28a9c252100f830433f4b37a73f4a61ba745bbeef4cdccbab48c1e9adf037f4ca3491 +"@babel/helper-validator-option@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-validator-option@npm:7.24.7" + checksum: 10c0/21aea2b7bc5cc8ddfb828741d5c8116a84cbc35b4a3184ec53124f08e09746f1f67a6f9217850188995ca86059a7942e36d8965a6730784901def777b7e8a436 languageName: node linkType: hard -"@babel/helper-wrap-function@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helper-wrap-function@npm:7.24.6" +"@babel/helper-wrap-function@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-wrap-function@npm:7.24.7" dependencies: - "@babel/helper-function-name": "npm:^7.24.6" - "@babel/template": "npm:^7.24.6" - "@babel/types": "npm:^7.24.6" - checksum: 10c0/d32844275a544a8e7c71c13e9832d34d80656aafce659dc6c23b02e14d1c1179d8045125ded5096da1a99de83299ffb48211183d0403da2c8584ed55dc0ab646 + "@babel/helper-function-name": "npm:^7.24.7" + "@babel/template": "npm:^7.24.7" + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/d5689f031bf0eb38c0d7fad6b7e320ddef4bfbdf08d12d7d76ef41b7ca365a32721e74cb5ed5a9a9ec634bc20f9b7a27314fa6fb08f1576b8f6d8330fcea6f47 languageName: node linkType: hard -"@babel/helpers@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/helpers@npm:7.24.6" +"@babel/helpers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helpers@npm:7.24.7" dependencies: - "@babel/template": "npm:^7.24.6" - "@babel/types": "npm:^7.24.6" - checksum: 10c0/e5b5c0919fd6fa56ae11c15a72962d8de0ac19db524849554af28cf08ac32f9ae5aee49a43146eb150f54418cefb8e890fa2b2f33d029434dc7777dbcdfd5bac + "@babel/template": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/aa8e230f6668773e17e141dbcab63e935c514b4b0bf1fed04d2eaefda17df68e16b61a56573f7f1d4d1e605ce6cc162b5f7e9fdf159fde1fd9b77c920ae47d27 languageName: node linkType: hard -"@babel/highlight@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/highlight@npm:7.24.6" +"@babel/highlight@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/highlight@npm:7.24.7" dependencies: - "@babel/helper-validator-identifier": "npm:^7.24.6" + "@babel/helper-validator-identifier": "npm:^7.24.7" chalk: "npm:^2.4.2" js-tokens: "npm:^4.0.0" picocolors: "npm:^1.0.0" - checksum: 10c0/5bbc31695e5d44e97feb267f7aaf4c52908560d184ffeb2e2e57aae058d40125592931883889413e19def3326895ddb41ff45e090fa90b459d8c294b4ffc238c + checksum: 10c0/674334c571d2bb9d1c89bdd87566383f59231e16bcdcf5bb7835babdf03c9ae585ca0887a7b25bdf78f303984af028df52831c7989fecebb5101cc132da9393a languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/parser@npm:7.24.6" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/parser@npm:7.24.7" bin: parser: ./bin/babel-parser.js - checksum: 10c0/cbef70923078a20fe163b03f4a6482be65ed99d409a57f3091a23ce3a575ee75716c30e7ea9f40b692ac5660f34055f4cbeb66a354fad15a6cf1fca35c3496c5 + checksum: 10c0/8b244756872185a1c6f14b979b3535e682ff08cb5a2a5fd97cc36c017c7ef431ba76439e95e419d43000c5b07720495b00cf29a7f0d9a483643d08802b58819b languageName: node linkType: hard -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.6" +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.7" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/0dbf12de5a7e5d092271124f0d9bff1ceb94871d5563041940512671cd40ab2a93d613715ee37076cd8263cf49579afb805faa3189996c11639bb10d3e9837f1 + checksum: 10c0/394c30e2b708ad385fa1219528e039066a1f1cb40f47986f283878848fd354c745e6397f588b4e5a046ee8d64bfdf4c208e4c3dfbdcfb2fd34315ec67c64e7af languageName: node linkType: hard -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.24.6" +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/b0a03d4f587e1fa92312c912864a0af3f68bfc87367b7c93770e94f171767d563d7adfca7ad571d20cd755e89e1373e7414973ce30e694e7b6eb8f57d2b1b889 + checksum: 10c0/a36307428ecc1a01b00cf90812335eed1575d13f211ab24fe4d0c55c28a2fcbd4135f142efabc3b277b2a8e09ee05df594a1272353f061b63829495b5dcfdb96 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.6" +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" - "@babel/plugin-transform-optional-chaining": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.13.0 - checksum: 10c0/fdd40fdf7e87f3dbc5396c9a8f92005798865f6f20d2c24c33246ac43aab8df93742b63dfcfcda67c0a5cf1f7b8a987fdbccaceb9ccbb9a67bef10012b522390 + checksum: 10c0/aeb6e7aa363a47f815cf956ea1053c5dd8b786a17799f065c9688ba4b0051fe7565d258bbe9400bfcbfb3114cb9fda66983e10afe4d750bc70ff75403e15dd36 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.24.6" +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.24.7" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/cc1e8ee138c71e78ec262a5198d2cf75c305f2fb4ea9771ebd4ded47f51bc1bacbf917db3cb28c681e7499a07f9803ab0bbe5ad50b9576cbe03902189e3871ed + checksum: 10c0/2b52a73e444f6adc73f927b623e53a4cf64397170dd1071268536df1b3db1e02131418c8dc91351af48837a6298212118f4a72d5407f8005cf9a732370a315b0 languageName: node linkType: hard @@ -496,25 +504,25 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-assertions@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-syntax-import-assertions@npm:7.24.6" +"@babel/plugin-syntax-import-assertions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/8e81c7cd3d5812a3dda32f06f84492a1b5640f42c594619ed57bf4017529889f87bfb4e8e95c50ba1527d89501dae71a0c73770502676545c2cd9ce58ce3258d + checksum: 10c0/b82c53e095274ee71c248551352d73441cf65b3b3fc0107258ba4e9aef7090772a425442b3ed1c396fa207d0efafde8929c87a17d3c885b3ca2021316e87e246 languageName: node linkType: hard -"@babel/plugin-syntax-import-attributes@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.6" +"@babel/plugin-syntax-import-attributes@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c4d8554b89c0daa6d3c430582b98c10a3af2de8eab484082e97cb73f2712780ab6dd8d11d783c4b266efef76f4479abf4944ef8f416a4459b05eecaf438f8774 + checksum: 10c0/eccc54d0f03c96d0eec7a6e2fa124dadbc7298345b62ffc4238f173308c4325b5598f139695ff05a95cf78412ef6903599e4b814496612bf39aad4715a16375b languageName: node linkType: hard @@ -540,14 +548,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:7, @babel/plugin-syntax-jsx@npm:^7.24.6, @babel/plugin-syntax-jsx@npm:^7.7.2": - version: 7.24.6 - resolution: "@babel/plugin-syntax-jsx@npm:7.24.6" +"@babel/plugin-syntax-jsx@npm:7, @babel/plugin-syntax-jsx@npm:^7.24.7, @babel/plugin-syntax-jsx@npm:^7.7.2": + version: 7.24.7 + resolution: "@babel/plugin-syntax-jsx@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/f00d783a9e2d52f0a8797823a3cbdbe2d0dc09c7235fe8c88e6dce3a02f234f52fb5e976a001cc30b0e2b330590b5680f54436e56d67f9ab05d1e4bdeb3992cd + checksum: 10c0/f44d927a9ae8d5ef016ff5b450e1671e56629ddc12e56b938e41fd46e141170d9dfc9a53d6cb2b9a20a7dd266a938885e6a3981c60c052a2e1daed602ac80e51 languageName: node linkType: hard @@ -639,14 +647,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.24.6, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.24.6 - resolution: "@babel/plugin-syntax-typescript@npm:7.24.6" +"@babel/plugin-syntax-typescript@npm:^7.24.7, @babel/plugin-syntax-typescript@npm:^7.7.2": + version: 7.24.7 + resolution: "@babel/plugin-syntax-typescript@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/b1eeabf8bebfa78cea559c0a0d55e480fe2ebd799472d1f6bd5afbd2759d02b362d29ad30009c81d5b112797beb987e58a3000d2331adaa4bf03862e1ed18cef + checksum: 10c0/cdabd2e8010fb0ad15b49c2c270efc97c4bfe109ead36c7bbcf22da7a74bc3e49702fc4f22f12d2d6049e8e22a5769258df1fd05f0420ae45e11bdd5bc07805a languageName: node linkType: hard @@ -662,456 +670,456 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-arrow-functions@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.6" +"@babel/plugin-transform-arrow-functions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/46250eb3f535327825db323740a301b76b882b70979f1fb5f89cbb1a820378ab68ee880b912981dd5276dd116deaaee0f4a2a95f1c9cf537a67749fd4209a2d3 + checksum: 10c0/6ac05a54e5582f34ac6d5dc26499e227227ec1c7fa6fc8de1f3d40c275f140d3907f79bbbd49304da2d7008a5ecafb219d0b71d78ee3290ca22020d878041245 languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.24.6" +"@babel/plugin-transform-async-generator-functions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.24.7" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-remap-async-to-generator": "npm:^7.24.6" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-remap-async-to-generator": "npm:^7.24.7" "@babel/plugin-syntax-async-generators": "npm:^7.8.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/8876431855220ccfbf1ae510a4a7c4e0377b21189d3f73ea6dde5ffd31eee57f03ea2b2d1da59b6a36b6e107e41b38d0c1d1bb015e0d1c2c2fb627962260edb7 + checksum: 10c0/6b5e33ae66dce0afce9b06d8dace6fa052528e60f7622aa6cfd3e71bd372ca5079d426e78336ca564bc0d5f37acbcda1b21f4fe656fcb642f1a93a697ab39742 languageName: node linkType: hard -"@babel/plugin-transform-async-to-generator@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.6" +"@babel/plugin-transform-async-to-generator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.7" dependencies: - "@babel/helper-module-imports": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-remap-async-to-generator": "npm:^7.24.6" + "@babel/helper-module-imports": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-remap-async-to-generator": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/52c137668e7a35356c3b1caf25ab3bf90ff61199885bfd9f0232bfe168a53a5cf0ca4c1e283c27e44ad76cc366b73e4ff7042241469d1944c7042fb78c57bfd8 + checksum: 10c0/83c82e243898875af8457972a26ab29baf8a2078768ee9f35141eb3edff0f84b165582a2ff73e90a9e08f5922bf813dbf15a85c1213654385198f4591c0dc45d languageName: node linkType: hard -"@babel/plugin-transform-block-scoped-functions@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.6" +"@babel/plugin-transform-block-scoped-functions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/0c761b5e3a2959b63edf47d67f6752e01f24777ad1accd82457a2dca059877f8a8297fbc7a062db6b48836309932f2ac645c507070ef6ad4e765b3600822c048 + checksum: 10c0/113e86de4612ae91773ff5cb6b980f01e1da7e26ae6f6012127415d7ae144e74987bc23feb97f63ba4bc699331490ddea36eac004d76a20d5369e4cc6a7f61cd languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-block-scoping@npm:7.24.6" +"@babel/plugin-transform-block-scoping@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-block-scoping@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/95c25e501c4553515f92d4e86032a8859a8855cea8aafb6df30f956979caa70af1e126e6dfaf9e51328d1306232ff1e081bda7d84a9aaf23f418d9da120c7018 + checksum: 10c0/dcbc5e385c0ca5fb5736b1c720c90755cffe9f91d8c854f82e61e59217dd3f6c91b3633eeee4b55a89d3f59e5275d0f5b0b1b1363d4fa70c49c468b55aa87700 languageName: node linkType: hard -"@babel/plugin-transform-class-properties@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-class-properties@npm:7.24.6" +"@babel/plugin-transform-class-properties@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-class-properties@npm:7.24.7" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/ae01e00dd528112d542a77f0f1cf6b43726553d2011bbdec9e4fac441dfa161d44bf14449dc4121b45cc971686a8c652652032594e83c5d6cab8e9fd794eecb2 + checksum: 10c0/75018a466c7ede3d2397e158891c224ba7fca72864506ce067ddbc02fc65191d44da4d6379c996d0c7f09019e26b5c3f5f1d3a639cd98366519723886f0689d0 languageName: node linkType: hard -"@babel/plugin-transform-class-static-block@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-class-static-block@npm:7.24.6" +"@babel/plugin-transform-class-static-block@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-class-static-block@npm:7.24.7" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.12.0 - checksum: 10c0/425f237faf62b531d973f23ac3eefe3f29c4f6c988c33c2dd660b6dfb61d4ed1e865a5088574742d87ed02437d26aa6ec6b107468b7df35ca9d3082bad742d8f + checksum: 10c0/b0ade39a3d09dce886f79dbd5907c3d99b48167eddb6b9bbde24a0598129654d7017e611c20494cdbea48b07ac14397cd97ea34e3754bbb2abae4e698128eccb languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-classes@npm:7.24.6" +"@babel/plugin-transform-classes@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-classes@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" - "@babel/helper-compilation-targets": "npm:^7.24.6" - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-function-name": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-replace-supers": "npm:^7.24.6" - "@babel/helper-split-export-declaration": "npm:^7.24.6" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-compilation-targets": "npm:^7.24.7" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-function-name": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.24.7" + "@babel/helper-split-export-declaration": "npm:^7.24.7" globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d29c26feea9ad5a64d790aeab1833b7a50d6af2be24140dad7e06510b754b8fe0ffb292d43d96fedaf7765fcb90c0034ac7c42635f814d9235697431076a1cf0 + checksum: 10c0/e51dba7ce8b770d1eee929e098d5a3be3efc3e8b941e22dda7d0097dc4e7be5feabd2da7b707ac06fcac5661b31223c541941dec08ce76c1faa55544d87d06ec languageName: node linkType: hard -"@babel/plugin-transform-computed-properties@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-computed-properties@npm:7.24.6" +"@babel/plugin-transform-computed-properties@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-computed-properties@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/template": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/template": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c464144c2eda8d526d70c8d8e3bf30820f591424991452f816617347ef3ccc5d04133c6e903b90c1d832d95d9c8550e5693ea40ea14856ede54fb8e1cd36c5de + checksum: 10c0/25636dbc1f605c0b8bc60aa58628a916b689473d11551c9864a855142e36742fe62d4a70400ba3b74902338e77fb3d940376c0a0ba154b6b7ec5367175233b49 languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-destructuring@npm:7.24.6" +"@babel/plugin-transform-destructuring@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-destructuring@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/1fcc064e2b0c45a4340418bd70d2cf2b3644d1215eb975ec14f83e4f7615fdc3948e355db5091f81602f6c3d933f9308caa66232091aad4edd6c16b00240fcc7 + checksum: 10c0/929f07a807fb62230bfbf881cfcedf187ac5daf2f1b01da94a75c7a0f6f72400268cf4bcfee534479e43260af8193e42c31ee03c8b0278ba77d0036ed6709c27 languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.6" +"@babel/plugin-transform-dotall-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/4a2c98f1c22a18754c6ada1486563865690008df2536066d8a146fa58eed8515b607e162c7efb0b8fa062d755e77afea145495046cffdb4ea56194d38f489254 + checksum: 10c0/793f14c9494972d294b7e7b97b747f47874b6d57d7804d3443c701becf5db192c9311be6a1835c07664486df1f5c60d33196c36fb7e11a53015e476b4c145b33 languageName: node linkType: hard -"@babel/plugin-transform-duplicate-keys@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.6" +"@babel/plugin-transform-duplicate-keys@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/44ddba252f0b9f1f0b1ff8d903bbcf8871246670fb2883f65d09d371d403ce9c3e2e582b94b36506c1d042110b464eb3492e53cd1e87c1d479b145bcc01c04fd + checksum: 10c0/75ff7ec1117ac500e77bf20a144411d39c0fdd038f108eec061724123ce6d1bb8d5bd27968e466573ee70014f8be0043361cdb0ef388f8a182d1d97ad67e51b9 languageName: node linkType: hard -"@babel/plugin-transform-dynamic-import@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.6" +"@babel/plugin-transform-dynamic-import@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/b4411f21112127a02aef15103765e207e4c03e7321d7f4de3522fc181cb377c5abc8484cf0169e6c30f2e51e6c602c09894fa6b15643d24f66273833ef34e4a6 + checksum: 10c0/eeda48372efd0a5103cb22dadb13563c975bce18ae85daafbb47d57bb9665d187da9d4fe8d07ac0a6e1288afcfcb73e4e5618bf75ff63fddf9736bfbf225203b languageName: node linkType: hard -"@babel/plugin-transform-exponentiation-operator@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.6" +"@babel/plugin-transform-exponentiation-operator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.7" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c4f15518a5d1614dfac0dbadfb99b0f36a98c1c1ff1c39794a105c3c87cfce00689e0943fcb13368b43b00b2eebaa01136ea12fb8600a574720853b5a8a11de7 + checksum: 10c0/ace3e11c94041b88848552ba8feb39ae4d6cad3696d439ff51445bd2882d8b8775d85a26c2c0edb9b5e38c9e6013cc11b0dea89ec8f93c7d9d7ee95e3645078c languageName: node linkType: hard -"@babel/plugin-transform-export-namespace-from@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.6" +"@babel/plugin-transform-export-namespace-from@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/bff16d1800d7e5b38d3a3c8d404cc14442a37383dff7769dcc599a0723b2507647cafe9ba7d9b52d2e2f02a78bb78d149676d8d8ddf7357b160f4096b89ae9c5 + checksum: 10c0/4e144d7f1c57bc63b4899dbbbdfed0880f2daa75ea9c7251c7997f106e4b390dc362175ab7830f11358cb21f6b972ca10a43a2e56cd789065f7606b082674c0c languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-for-of@npm:7.24.6" +"@babel/plugin-transform-for-of@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-for-of@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c8def2a160783c5c4a1c136c721fc88aca9cd3757a60f1c885a804b5320edb5f143d3f989f698bdd9aae359fdabab0830dba3d35138cea42988a77d2c72c8443 + checksum: 10c0/77629b1173e55d07416f05ba7353caa09d2c2149da2ca26721ab812209b63689d1be45116b68eadc011c49ced59daf5320835b15245eb7ae93ae0c5e8277cfc0 languageName: node linkType: hard -"@babel/plugin-transform-function-name@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-function-name@npm:7.24.6" +"@babel/plugin-transform-function-name@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-function-name@npm:7.24.7" dependencies: - "@babel/helper-compilation-targets": "npm:^7.24.6" - "@babel/helper-function-name": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-compilation-targets": "npm:^7.24.7" + "@babel/helper-function-name": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/efa6527438ad94df0b7a4c92c33110ec40b086a0aceda567176b150ed291f8eb44b2ce697d8e3e1d4841496c10693add1e88f296418e72a171ead5c76b890a47 + checksum: 10c0/3e9642428d6952851850d89ea9307d55946528d18973784d0e2f04a651b23bd9924dd8a2641c824b483bd4ab1223bab1d2f6a1106a939998f7ced512cb60ac5b languageName: node linkType: hard -"@babel/plugin-transform-json-strings@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-json-strings@npm:7.24.6" +"@babel/plugin-transform-json-strings@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-json-strings@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-json-strings": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/46af52dcc16f494c6c11dc22c944f2533623b9d9dfce5097bc0bdb99535ad4c4cfe5bca0d8ce8c39a94202e69d99ee60f546ce0be0ad782b681c7b5b4c9ddd6f + checksum: 10c0/17c72cd5bf3e90e722aabd333559275f3309e3fa0b9cea8c2944ab83ae01502c71a2be05da5101edc02b3fc8df15a8dbb9b861cbfcc8a52bf5e797cf01d3a40a languageName: node linkType: hard -"@babel/plugin-transform-literals@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-literals@npm:7.24.6" +"@babel/plugin-transform-literals@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-literals@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/961b64df79a673706d74cf473d1f4646f250b4f8813f9d7ef5d897e30acdacd1ca104584de2e88546289fce055d71bd7559cdb8ad4a2d5e7eea17f3c829faa97 + checksum: 10c0/9f3f6f3831929cd2a977748c07addf9944d5cccb50bd3a24a58beb54f91f00d6cacd3d7831d13ffe1ad6f8aba0aefd7bca5aec65d63b77f39c62ad1f2d484a3e languageName: node linkType: hard -"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.6" +"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/0ae7f4098c63f442fd038de6034155bcf20214e7e490e92189decb2980932247b97cb069b11ac8bc471b53f71d6859e607969440d63ff400b8932ee3e05b4958 + checksum: 10c0/dbe882eb9053931f2ab332c50fc7c2a10ef507d6421bd9831adbb4cb7c9f8e1e5fbac4fbd2e007f6a1bf1df1843547559434012f118084dc0bf42cda3b106272 languageName: node linkType: hard -"@babel/plugin-transform-member-expression-literals@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.6" +"@babel/plugin-transform-member-expression-literals@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/ec8908a409bd39d20f0428e35425c9e4c540bad252a0e33e08b84e3bea5088c785531197bdcf049afbdba841325962a93030b7be6da3586cb13d0ca0ebab89c9 + checksum: 10c0/e789ae359bdf2d20e90bedef18dfdbd965c9ebae1cee398474a0c349590fda7c8b874e1a2ceee62e47e5e6ec1730e76b0f24e502164357571854271fc12cc684 languageName: node linkType: hard -"@babel/plugin-transform-modules-amd@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-modules-amd@npm:7.24.6" +"@babel/plugin-transform-modules-amd@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-modules-amd@npm:7.24.7" dependencies: - "@babel/helper-module-transforms": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-module-transforms": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/074d26c79f517b27a07fef00319aff9705df1e6b41a805db855fe719e0f246b9815d6525cf1c5f0890c7f830dd0b9776e9b2493bbc929a3c23c0dee15f10a514 + checksum: 10c0/6df7de7fce34117ca4b2fa07949b12274c03668cbfe21481c4037b6300796d50ae40f4f170527b61b70a67f26db906747797e30dbd0d9809a441b6e220b5728f languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.6" +"@babel/plugin-transform-modules-commonjs@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.7" dependencies: - "@babel/helper-module-transforms": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-simple-access": "npm:^7.24.6" + "@babel/helper-module-transforms": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-simple-access": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/4fc790136d066105fa773ffc7e249d88c6f0d0126984ede36fedd51ac2b622b46c08565bcdd1ab62ac10195eeedeaba0d26e7e4c676ed50906cbed16540a4e22 + checksum: 10c0/9442292b3daf6a5076cdc3c4c32bf423bda824ccaeb0dd0dc8b3effaa1fecfcb0130ae6e647fef12a5d5ff25bcc99a0d6bfc6d24a7525345e1bcf46fcdf81752 languageName: node linkType: hard -"@babel/plugin-transform-modules-systemjs@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.24.6" +"@babel/plugin-transform-modules-systemjs@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.24.7" dependencies: - "@babel/helper-hoist-variables": "npm:^7.24.6" - "@babel/helper-module-transforms": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-validator-identifier": "npm:^7.24.6" + "@babel/helper-hoist-variables": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-validator-identifier": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/500962e3ac1bb1a9890e94f1967ec9e3aa3d41e22d4a9d1c739918707e4a8936710fd8d0ed4f3a8aad87260f7566b54566bead77977eb21e90124835cb6bcdca + checksum: 10c0/e2a795e0a6baafe26f4a74010622212ddd873170742d673f450e0097f8d984f6e6a95eb8ce41b05071ee9790c4be088b33801aaab3f78ee202c567634e52a331 languageName: node linkType: hard -"@babel/plugin-transform-modules-umd@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-modules-umd@npm:7.24.6" +"@babel/plugin-transform-modules-umd@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-modules-umd@npm:7.24.7" dependencies: - "@babel/helper-module-transforms": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-module-transforms": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/73c6cecb4f45ca3f665e2c57b6d04d65358518522dfaffb9b6913c026aeb704281d015324d02bf07f2cb026de6bac9308c62e82979364bd39f3687f752652b0d + checksum: 10c0/7791d290121db210e4338b94b4a069a1a79e4c7a8d7638d8159a97b281851bbed3048dac87a4ae718ad963005e6c14a5d28e6db2eeb2b04e031cee92fb312f85 languageName: node linkType: hard -"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.24.6" +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/92547309d81938488753f87b05a679a7557a1cec253756966044367c268b27311e51efad91724aa3e433cf61626e10bf1008e112998350c2013a87824c4cfe0b + checksum: 10c0/41a0b0f2d0886318237440aa3b489f6d0305361d8671121777d9ff89f9f6de9d0c02ce93625049061426c8994064ef64deae8b819d1b14c00374a6a2336fb5d9 languageName: node linkType: hard -"@babel/plugin-transform-new-target@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-new-target@npm:7.24.6" +"@babel/plugin-transform-new-target@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-new-target@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/5e9b9edfbe46489f64013d2bbd422f29acdb8057ccc85e7c759f7cf1415fde6a82ac13a13f0f246defaba6e2f7f4d424178ba78fc02237bdbf7df6692fc1dca8 + checksum: 10c0/2540808a35e1a978e537334c43dab439cf24c93e7beb213a2e71902f6710e60e0184316643790c0a6644e7a8021e52f7ab8165e6b3e2d6651be07bdf517b67df languageName: node linkType: hard -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.6" +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/53ab5b16bbcf47e842a48f1f0774d238dae0222c3e1f31653307808048e249ed140cba12dfc280cbc9a577cb3bb5b2f50ca0e3e4ffe5260fcf8c3ca0b83fb21e + checksum: 10c0/7243c8ff734ed5ef759dd8768773c4b443c12e792727e759a1aec2c7fa2bfdd24f1ecb42e292a7b3d8bd3d7f7b861cf256a8eb4ba144fc9cc463892c303083d9 languageName: node linkType: hard -"@babel/plugin-transform-numeric-separator@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.6" +"@babel/plugin-transform-numeric-separator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/14863e735fc407e065e1574914864a956b8250a84cfb4704592656763c9455d67034c7745e53066725195d9ed042121f424c4aaee00027791640e2639386b701 + checksum: 10c0/e18e09ca5a6342645d00ede477731aa6e8714ff357efc9d7cda5934f1703b3b6fb7d3298dce3ce3ba53e9ff1158eab8f1aadc68874cc21a6099d33a1ca457789 languageName: node linkType: hard -"@babel/plugin-transform-object-rest-spread@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.6" +"@babel/plugin-transform-object-rest-spread@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.7" dependencies: - "@babel/helper-compilation-targets": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-compilation-targets": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-transform-parameters": "npm:^7.24.6" + "@babel/plugin-transform-parameters": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/1a192b9756ebfa0bc69ad5e285d7d0284963b4b95738ca7721354297329d5c1ab4eb05ff5b198cbfffa3ec00e97a15a712aa7a5011d9407478796966aab54527 + checksum: 10c0/9ad64bc003f583030f9da50614b485852f8edac93f8faf5d1cd855201a4852f37c5255ae4daf70dd4375bdd4874e16e39b91f680d4668ec219ba05441ce286eb languageName: node linkType: hard -"@babel/plugin-transform-object-super@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-object-super@npm:7.24.6" +"@babel/plugin-transform-object-super@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-object-super@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-replace-supers": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/2e48b9e0a1f3b04b439ede2d0c83bcc5324a81c8bab73c70f0c466cf48061a4ff469f283e2feb17b4cc2e20372c1362253604477ecd77e622192d5d7906aa062 + checksum: 10c0/770cebb4b4e1872c216b17069db9a13b87dfee747d359dc56d9fcdd66e7544f92dc6ab1861a4e7e0528196aaff2444e4f17dc84efd8eaf162d542b4ba0943869 languageName: node linkType: hard -"@babel/plugin-transform-optional-catch-binding@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.6" +"@babel/plugin-transform-optional-catch-binding@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/411db3177b1bffd2f9e5b33a6b62e70158380e67d91ff4725755312e8a0a2f2c3fd340c60005295a672115fb593222ab2d7076266aebced6ef087a5505b6f371 + checksum: 10c0/1e2f10a018f7d03b3bde6c0b70d063df8d5dd5209861d4467726cf834f5e3d354e2276079dc226aa8e6ece35f5c9b264d64b8229a8bb232829c01e561bcfb07a languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.6" +"@babel/plugin-transform-optional-chaining@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/8ee5a500a2309444d4fb27979857598e9c91d804fe23217c51cc208b1bc6b9cd0650b355b1ebd625f180c5f1dc4cb89b5f313c982f7c89d90281a69b24a88ccb + checksum: 10c0/b9e3649b299e103b0d1767bbdba56574d065ff776e5350403b7bfd4e3982743c0cdb373d33bdbf94fa3c322d155e45d0aad946acf0aa741b870aed22dfec8b8e languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-parameters@npm:7.24.6" +"@babel/plugin-transform-parameters@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-parameters@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d9648924b9c0d35a243c0742c22838932a024205c61f4cc419857e5195edd893a33e6be4f2c8fbd89e925051c7cbe8968029ec2d3e7f2f098bfa682f4e2b9731 + checksum: 10c0/53bf190d6926771545d5184f1f5f3f5144d0f04f170799ad46a43f683a01fab8d5fe4d2196cf246774530990c31fe1f2b9f0def39f0a5ddbb2340b924f5edf01 languageName: node linkType: hard -"@babel/plugin-transform-private-methods@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-private-methods@npm:7.24.6" +"@babel/plugin-transform-private-methods@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-private-methods@npm:7.24.7" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/55f93959b2e8aeda818db7cdc7dfdcd5076f5bdc8a819566818004a68969fb7297d617f9d108bf76ac232d6056d9f9d20f73ce10380baa43ff1755c5591aa803 + checksum: 10c0/5b7bf923b738fbe3ad6c33b260e0a7451be288edfe4ef516303fa787a1870cd87533bfbf61abb779c22ed003c2fc484dec2436fe75a48756f686c0241173d364 languageName: node linkType: hard -"@babel/plugin-transform-private-property-in-object@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.6" +"@babel/plugin-transform-private-property-in-object@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" - "@babel/helper-create-class-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c9eb9597362b598a91536375a49ba80cdf13461e849680e040898b103f7998c4d33a7832da5afba9fa51e3473f79cf8605f9ace07a887e386b7801797021631b + checksum: 10c0/c6fa7defb90b1b0ed46f24ff94ff2e77f44c1f478d1090e81712f33cf992dda5ba347016f030082a2f770138bac6f4a9c2c1565e9f767a125901c77dd9c239ba languageName: node linkType: hard -"@babel/plugin-transform-property-literals@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-property-literals@npm:7.24.6" +"@babel/plugin-transform-property-literals@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-property-literals@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d1195d93406b6c400cdbc9ac57a2b8b58c72cc6480cc03656abfc243be0e2a48133cbb96559c2db95b1c78803daeb538277821540fe19e2a9105905e727ef618 + checksum: 10c0/52564b58f3d111dc02d241d5892a4b01512e98dfdf6ef11b0ed62f8b11b0acacccef0fc229b44114fe8d1a57a8b70780b11bdd18b807d3754a781a07d8f57433 languageName: node linkType: hard @@ -1126,243 +1134,243 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-display-name@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-react-display-name@npm:7.24.6" +"@babel/plugin-transform-react-display-name@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-react-display-name@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e929d054035fa3b7432bd2b3e5cf280ffd8cf60d1ce80c863c5e0b03ad01bf6ae2546575d2da31cca2ab83d9399ac01a351f20e21af5075d9c0d4c893e4a36bd + checksum: 10c0/c14a07a9e75723c96f1a0a306b8a8e899ff1c6a0cc3d62bcda79bb1b54e4319127b258651c513a1a47da152cdc22e16525525a30ae5933a2980c7036fd0b4d24 languageName: node linkType: hard "@babel/plugin-transform-react-inline-elements@npm:^7.21.0": - version: 7.24.6 - resolution: "@babel/plugin-transform-react-inline-elements@npm:7.24.6" + version: 7.24.7 + resolution: "@babel/plugin-transform-react-inline-elements@npm:7.24.7" dependencies: - "@babel/helper-builder-react-jsx": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-builder-react-jsx": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/b29f32a0c345db24f32569cf7a5626e37dd31c21bb764148757e91f609d41e2d09031ff1ad86e5672d578cf16f513b197ef3ebc8f0650d8314890a34ca68f02c + checksum: 10c0/affe44efc641e5dc4de077db74c80e3dee896a5dfea04491cbd8167ac40dcbb6eaa1ad0ba599e4a85071acdaa08732e7f5d9cf3236a2aa635406c232c8f08236 languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-development@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-react-jsx-development@npm:7.24.6" +"@babel/plugin-transform-react-jsx-development@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.24.7" dependencies: - "@babel/plugin-transform-react-jsx": "npm:^7.24.6" + "@babel/plugin-transform-react-jsx": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/f899ffa65c7f459a682246a346af0e4132929ffe928cb0d02ae08aac1cf3fb01b2f6e944ef1eaca78f14e94eff935e2bf96aad878030c25ff6de2070a8b72448 + checksum: 10c0/fce647db50f90a5291681f0f97865d9dc76981262dff71d6d0332e724b85343de5860c26f9e9a79e448d61e1d70916b07ce91e8c7f2b80dceb4b16aee41794d8 languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-react-jsx@npm:7.24.6" +"@babel/plugin-transform-react-jsx@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-react-jsx@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" - "@babel/helper-module-imports": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/plugin-syntax-jsx": "npm:^7.24.6" - "@babel/types": "npm:^7.24.6" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-module-imports": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-jsx": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6144f56a76529a82077475583a17be8f0b0b461c83673e650f3894e09dbe2bcdfdbfff089eca2e5e239e119f72cd9562749a9af7eb3f2e3266a730da31cd19f2 + checksum: 10c0/5c46d2c1c06a30e6bde084839df9cc689bf9c9cb0292105d61c225ca731f64247990724caee7dfc7f817dc964c062e8319e7f05394209590c476b65d75373435 languageName: node linkType: hard -"@babel/plugin-transform-react-pure-annotations@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.24.6" +"@babel/plugin-transform-react-pure-annotations@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/7f83c5a3a275dbb9a291dee4642a3a0f2249265346d8d3cc9324fc9ee063c3e35c3853b52752ece603f0ac92b405deb38c4b5307a99a74d3e1c9c32a2cefa465 + checksum: 10c0/fae517d293d9c93b7b920458c3e4b91cb0400513889af41ba184a5f3acc8bfef27242cc262741bb8f87870df376f1733a0d0f52b966d342e2aaaf5607af8f73d languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-regenerator@npm:7.24.6" +"@babel/plugin-transform-regenerator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-regenerator@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" regenerator-transform: "npm:^0.15.2" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d17eaa97514d583866182420024b8c22da2c6ca822bdbf16fe7564121564c1844935592dc3315c73d1f78f7c908a4338b1d783618811e694c9bb6d5f9233e58d + checksum: 10c0/d2dc2c788fdae9d97217e70d46ba8ca9db0035c398dc3e161552b0c437113719a75c04f201f9c91ddc8d28a1da60d0b0853f616dead98a396abb9c845c44892b languageName: node linkType: hard -"@babel/plugin-transform-reserved-words@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-reserved-words@npm:7.24.6" +"@babel/plugin-transform-reserved-words@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-reserved-words@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/5d2d4c579bd90c60fc6468a1285b3384e7b650b47d41a937a1590d4aecfc28bd945e82704c6e71cc91aa016b7e78c5594290c1c386edf11ec98e09e36235c5ae + checksum: 10c0/2229de2768615e7f5dc0bbc55bc121b5678fd6d2febd46c74a58e42bb894d74cd5955c805880f4e02d0e1cf94f6886270eda7fafc1be9305a1ec3b9fd1d063f5 languageName: node linkType: hard "@babel/plugin-transform-runtime@npm:^7.22.4": - version: 7.24.6 - resolution: "@babel/plugin-transform-runtime@npm:7.24.6" + version: 7.24.7 + resolution: "@babel/plugin-transform-runtime@npm:7.24.7" dependencies: - "@babel/helper-module-imports": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-module-imports": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" babel-plugin-polyfill-corejs2: "npm:^0.4.10" babel-plugin-polyfill-corejs3: "npm:^0.10.1" babel-plugin-polyfill-regenerator: "npm:^0.6.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/89c43c1236506ecbfc547b12936283ca41e611430c2d2e6d12bf1cbdb0d80760cdae481951f486946733e1c9ae064cb05f4bc779c65b3288d40963b0c4a20c5c + checksum: 10c0/a33f5095872bbba00b8ee553dfe6941477e69a017a2e65e9dd86e80dab5c627635093b796eb1eb22aaaf2f874704f63ad1d99b952b83b59ef6b368ae04e5bb41 languageName: node linkType: hard -"@babel/plugin-transform-shorthand-properties@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.6" +"@babel/plugin-transform-shorthand-properties@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/4141b5da1d0d20d66ca0affaef8dfc45ed5e954bfa9003eb8aa779842599de443b37c2b265da27693f304c35ab68a682b44098e9eea0d39f8f94072ab616657f + checksum: 10c0/41b155bdbb3be66618358488bf7731b3b2e8fff2de3dbfd541847720a9debfcec14db06a117abedd03c9cd786db20a79e2a86509a4f19513f6e1b610520905cf languageName: node linkType: hard -"@babel/plugin-transform-spread@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-spread@npm:7.24.6" +"@babel/plugin-transform-spread@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-spread@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6d12da05311690c4a73d775688ba6931b441e96e512377a166a60184292edeac0b17f5154a49e2f1d262a3f80b96e064bc9c88c63b2a6125f0a2132eff9ed585 + checksum: 10c0/facba1553035f76b0d2930d4ada89a8cd0f45b79579afd35baefbfaf12e3b86096995f4b0c402cf9ee23b3f2ea0a4460c3b1ec0c192d340962c948bb223d4e66 languageName: node linkType: hard -"@babel/plugin-transform-sticky-regex@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.6" +"@babel/plugin-transform-sticky-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/2a65f57554f51d3b9cd035513a610f47e46b26dba112b3b9fb42d1c1f2ae153fce8f76294b4721d099817814f57895c656f5b7dccd5df683277da6522c817ee9 + checksum: 10c0/5a74ed2ed0a3ab51c3d15fcaf09d9e2fe915823535c7a4d7b019813177d559b69677090e189ec3d5d08b619483eb5ad371fbcfbbff5ace2a76ba33ee566a1109 languageName: node linkType: hard -"@babel/plugin-transform-template-literals@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-template-literals@npm:7.24.6" +"@babel/plugin-transform-template-literals@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-template-literals@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/fcde48e9c3ecd7f5f37ceb6908f1edd537d3115fc2f27d187d58fd83b2a13637a1bb3d24589d841529ed081405b951bf1c5d194ea81eff6ad2d88204d153010d + checksum: 10c0/3630f966257bcace122f04d3157416a09d40768c44c3a800855da81146b009187daa21859d1c3b7d13f4e19e8888e60613964b175b2275d451200fb6d8d6cfe6 languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.6" +"@babel/plugin-transform-typeof-symbol@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/a24b3a3c7b87c6496ee13d2438effd4645868f054397357ec3cbe92a2f0df4152ac7fd7228cb956576c1b772c0675b065d6ad5f5053c382e97dd022015e9a028 + checksum: 10c0/5649e7260a138681e68b296ab5931e2b1f132f287d6b4131d49b24f9dc20d62902b7e9d63c4d2decd5683b41df35ef4b9b03f58c7f9f65e4c25a6d8bbf04e9e9 languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-typescript@npm:7.24.6" +"@babel/plugin-transform-typescript@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-typescript@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.6" - "@babel/helper-create-class-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/plugin-syntax-typescript": "npm:^7.24.6" + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-typescript": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/46b054e4d4253187403e392ef30f4dd624d8486a1992703f5ff1b415d4e8d00f474e35fb77bc7a3a16a17330873cadcd5af4a8493c61b16da2dde212b2788ccd + checksum: 10c0/e8dacdc153a4c4599014b66eb01b94e3dc933d58d4f0cc3039c1a8f432e77b9df14f34a61964e014b975bf466f3fefd8c4768b3e887d3da1be9dc942799bdfdf languageName: node linkType: hard -"@babel/plugin-transform-unicode-escapes@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.6" +"@babel/plugin-transform-unicode-escapes@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/0e4038c589b7a63a2469466a25b78aad4ecb7267732e3c953c3055f9a77c7bee859a71983a08b025179f1b094964f2ebbfca1b6c33de4ead90a0b5ef06ddb47e + checksum: 10c0/8b18e2e66af33471a6971289492beff5c240e56727331db1d34c4338a6a368a82a7ed6d57ec911001b6d65643aed76531e1e7cac93265fb3fb2717f54d845e69 languageName: node linkType: hard -"@babel/plugin-transform-unicode-property-regex@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.6" +"@babel/plugin-transform-unicode-property-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/bca99e00de91d0460dfcb25f285f3606248acc905193c05587e2862c54ddb790c5d8cb45e80927290390cffbcba7620f8af3e74c5301ff0c1c59ce7d47c5629f + checksum: 10c0/bc57656eb94584d1b74a385d378818ac2b3fca642e3f649fead8da5fb3f9de22f8461185936915dfb33d5a9104e62e7a47828331248b09d28bb2d59e9276de3e languageName: node linkType: hard -"@babel/plugin-transform-unicode-regex@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.6" +"@babel/plugin-transform-unicode-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/ab6e253cfc38c7e8a2844d7ad46f85fdcbe33610b7f92f71045cf0b040438a08f1f1717ab4b84c480537f54e5478db8b404a4ccc2ff846b4e3ed33d373e3b47a + checksum: 10c0/83f72a345b751566b601dc4d07e9f2c8f1bc0e0c6f7abb56ceb3095b3c9d304de73f85f2f477a09f8cc7edd5e65afd0ff9e376cdbcbea33bc0c28f3705b38fd9 languageName: node linkType: hard -"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.24.6" +"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/a52e84f85519fed330e88f7a17611064d2b5f1d0fe2823f8113ed312828e69787888bd023f404e8d35d0bb96461e42e19cdc4f0a44d35959bc86c219a3062237 + checksum: 10c0/7457c0ee8e80a80cb6fdc1fe54ab115b52815627616ce9151be8ef292fc99d04a910ec24f11382b4f124b89374264396892b086886bd2a9c2317904d87c9b21b languageName: node linkType: hard "@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4": - version: 7.24.6 - resolution: "@babel/preset-env@npm:7.24.6" + version: 7.24.7 + resolution: "@babel/preset-env@npm:7.24.7" dependencies: - "@babel/compat-data": "npm:^7.24.6" - "@babel/helper-compilation-targets": "npm:^7.24.6" - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-validator-option": "npm:^7.24.6" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.6" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.6" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.6" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.6" + "@babel/compat-data": "npm:^7.24.7" + "@babel/helper-compilation-targets": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-validator-option": "npm:^7.24.7" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.7" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.7" "@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators": "npm:^7.8.4" "@babel/plugin-syntax-class-properties": "npm:^7.12.13" "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" - "@babel/plugin-syntax-import-assertions": "npm:^7.24.6" - "@babel/plugin-syntax-import-attributes": "npm:^7.24.6" + "@babel/plugin-syntax-import-assertions": "npm:^7.24.7" + "@babel/plugin-syntax-import-attributes": "npm:^7.24.7" "@babel/plugin-syntax-import-meta": "npm:^7.10.4" "@babel/plugin-syntax-json-strings": "npm:^7.8.3" "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" @@ -1374,54 +1382,54 @@ __metadata: "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" - "@babel/plugin-transform-arrow-functions": "npm:^7.24.6" - "@babel/plugin-transform-async-generator-functions": "npm:^7.24.6" - "@babel/plugin-transform-async-to-generator": "npm:^7.24.6" - "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.6" - "@babel/plugin-transform-block-scoping": "npm:^7.24.6" - "@babel/plugin-transform-class-properties": "npm:^7.24.6" - "@babel/plugin-transform-class-static-block": "npm:^7.24.6" - "@babel/plugin-transform-classes": "npm:^7.24.6" - "@babel/plugin-transform-computed-properties": "npm:^7.24.6" - "@babel/plugin-transform-destructuring": "npm:^7.24.6" - "@babel/plugin-transform-dotall-regex": "npm:^7.24.6" - "@babel/plugin-transform-duplicate-keys": "npm:^7.24.6" - "@babel/plugin-transform-dynamic-import": "npm:^7.24.6" - "@babel/plugin-transform-exponentiation-operator": "npm:^7.24.6" - "@babel/plugin-transform-export-namespace-from": "npm:^7.24.6" - "@babel/plugin-transform-for-of": "npm:^7.24.6" - "@babel/plugin-transform-function-name": "npm:^7.24.6" - "@babel/plugin-transform-json-strings": "npm:^7.24.6" - "@babel/plugin-transform-literals": "npm:^7.24.6" - "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.6" - "@babel/plugin-transform-member-expression-literals": "npm:^7.24.6" - "@babel/plugin-transform-modules-amd": "npm:^7.24.6" - "@babel/plugin-transform-modules-commonjs": "npm:^7.24.6" - "@babel/plugin-transform-modules-systemjs": "npm:^7.24.6" - "@babel/plugin-transform-modules-umd": "npm:^7.24.6" - "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.6" - "@babel/plugin-transform-new-target": "npm:^7.24.6" - "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.6" - "@babel/plugin-transform-numeric-separator": "npm:^7.24.6" - "@babel/plugin-transform-object-rest-spread": "npm:^7.24.6" - "@babel/plugin-transform-object-super": "npm:^7.24.6" - "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.6" - "@babel/plugin-transform-optional-chaining": "npm:^7.24.6" - "@babel/plugin-transform-parameters": "npm:^7.24.6" - "@babel/plugin-transform-private-methods": "npm:^7.24.6" - "@babel/plugin-transform-private-property-in-object": "npm:^7.24.6" - "@babel/plugin-transform-property-literals": "npm:^7.24.6" - "@babel/plugin-transform-regenerator": "npm:^7.24.6" - "@babel/plugin-transform-reserved-words": "npm:^7.24.6" - "@babel/plugin-transform-shorthand-properties": "npm:^7.24.6" - "@babel/plugin-transform-spread": "npm:^7.24.6" - "@babel/plugin-transform-sticky-regex": "npm:^7.24.6" - "@babel/plugin-transform-template-literals": "npm:^7.24.6" - "@babel/plugin-transform-typeof-symbol": "npm:^7.24.6" - "@babel/plugin-transform-unicode-escapes": "npm:^7.24.6" - "@babel/plugin-transform-unicode-property-regex": "npm:^7.24.6" - "@babel/plugin-transform-unicode-regex": "npm:^7.24.6" - "@babel/plugin-transform-unicode-sets-regex": "npm:^7.24.6" + "@babel/plugin-transform-arrow-functions": "npm:^7.24.7" + "@babel/plugin-transform-async-generator-functions": "npm:^7.24.7" + "@babel/plugin-transform-async-to-generator": "npm:^7.24.7" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.7" + "@babel/plugin-transform-block-scoping": "npm:^7.24.7" + "@babel/plugin-transform-class-properties": "npm:^7.24.7" + "@babel/plugin-transform-class-static-block": "npm:^7.24.7" + "@babel/plugin-transform-classes": "npm:^7.24.7" + "@babel/plugin-transform-computed-properties": "npm:^7.24.7" + "@babel/plugin-transform-destructuring": "npm:^7.24.7" + "@babel/plugin-transform-dotall-regex": "npm:^7.24.7" + "@babel/plugin-transform-duplicate-keys": "npm:^7.24.7" + "@babel/plugin-transform-dynamic-import": "npm:^7.24.7" + "@babel/plugin-transform-exponentiation-operator": "npm:^7.24.7" + "@babel/plugin-transform-export-namespace-from": "npm:^7.24.7" + "@babel/plugin-transform-for-of": "npm:^7.24.7" + "@babel/plugin-transform-function-name": "npm:^7.24.7" + "@babel/plugin-transform-json-strings": "npm:^7.24.7" + "@babel/plugin-transform-literals": "npm:^7.24.7" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.7" + "@babel/plugin-transform-member-expression-literals": "npm:^7.24.7" + "@babel/plugin-transform-modules-amd": "npm:^7.24.7" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.7" + "@babel/plugin-transform-modules-systemjs": "npm:^7.24.7" + "@babel/plugin-transform-modules-umd": "npm:^7.24.7" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.7" + "@babel/plugin-transform-new-target": "npm:^7.24.7" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.7" + "@babel/plugin-transform-numeric-separator": "npm:^7.24.7" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.7" + "@babel/plugin-transform-object-super": "npm:^7.24.7" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.7" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.7" + "@babel/plugin-transform-parameters": "npm:^7.24.7" + "@babel/plugin-transform-private-methods": "npm:^7.24.7" + "@babel/plugin-transform-private-property-in-object": "npm:^7.24.7" + "@babel/plugin-transform-property-literals": "npm:^7.24.7" + "@babel/plugin-transform-regenerator": "npm:^7.24.7" + "@babel/plugin-transform-reserved-words": "npm:^7.24.7" + "@babel/plugin-transform-shorthand-properties": "npm:^7.24.7" + "@babel/plugin-transform-spread": "npm:^7.24.7" + "@babel/plugin-transform-sticky-regex": "npm:^7.24.7" + "@babel/plugin-transform-template-literals": "npm:^7.24.7" + "@babel/plugin-transform-typeof-symbol": "npm:^7.24.7" + "@babel/plugin-transform-unicode-escapes": "npm:^7.24.7" + "@babel/plugin-transform-unicode-property-regex": "npm:^7.24.7" + "@babel/plugin-transform-unicode-regex": "npm:^7.24.7" + "@babel/plugin-transform-unicode-sets-regex": "npm:^7.24.7" "@babel/preset-modules": "npm:0.1.6-no-external-plugins" babel-plugin-polyfill-corejs2: "npm:^0.4.10" babel-plugin-polyfill-corejs3: "npm:^0.10.4" @@ -1430,7 +1438,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d837d294197803d550e48d9458a356853a54a0528e7cdc51c2b8a5d8dfe41c6fbc597b4fc67464615a7385198a3db2e839da15cca7b9502fedf27170fc6ef673 + checksum: 10c0/c6714346f3ccc1271eaa90051c75b8bb57b20ef57408ab68740e2f3552693ae0ee5a4bcce3a00211d40e4947af1f7b8ab422066b953f0095461937fb72d11274 languageName: node linkType: hard @@ -1448,33 +1456,33 @@ __metadata: linkType: hard "@babel/preset-react@npm:^7.12.5, @babel/preset-react@npm:^7.22.3": - version: 7.24.6 - resolution: "@babel/preset-react@npm:7.24.6" + version: 7.24.7 + resolution: "@babel/preset-react@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-validator-option": "npm:^7.24.6" - "@babel/plugin-transform-react-display-name": "npm:^7.24.6" - "@babel/plugin-transform-react-jsx": "npm:^7.24.6" - "@babel/plugin-transform-react-jsx-development": "npm:^7.24.6" - "@babel/plugin-transform-react-pure-annotations": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-validator-option": "npm:^7.24.7" + "@babel/plugin-transform-react-display-name": "npm:^7.24.7" + "@babel/plugin-transform-react-jsx": "npm:^7.24.7" + "@babel/plugin-transform-react-jsx-development": "npm:^7.24.7" + "@babel/plugin-transform-react-pure-annotations": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/edc470b86dfcfdedf53feca3f2266bd7f836a300806938a422f4120d39bbdea6a780b9b0a9ac0333e0bb1b8e554699a74cafd135b2a75b02b77ef1b21f7c7f62 + checksum: 10c0/9658b685b25cedaadd0b65c4e663fbc7f57394b5036ddb4c99b1a75b0711fb83292c1c625d605c05b73413fc7a6dc20e532627f6a39b6dc8d4e00415479b054c languageName: node linkType: hard "@babel/preset-typescript@npm:^7.21.5": - version: 7.24.6 - resolution: "@babel/preset-typescript@npm:7.24.6" + version: 7.24.7 + resolution: "@babel/preset-typescript@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.6" - "@babel/helper-validator-option": "npm:^7.24.6" - "@babel/plugin-syntax-jsx": "npm:^7.24.6" - "@babel/plugin-transform-modules-commonjs": "npm:^7.24.6" - "@babel/plugin-transform-typescript": "npm:^7.24.6" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-validator-option": "npm:^7.24.7" + "@babel/plugin-syntax-jsx": "npm:^7.24.7" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.7" + "@babel/plugin-transform-typescript": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/bfcef91ed80d67301301e17a799814457b57bfd0d85d9897dce6df6ed0b0af155c0f5b2af7a1a122a3f36faaaa1de87ccf9954ce06d2f440898ffdfaf18aab86 + checksum: 10c0/986bc0978eedb4da33aba8e1e13a3426dd1829515313b7e8f4ba5d8c18aff1663b468939d471814e7acf4045d326ae6cff37239878d169ac3fe53a8fde71f8ee languageName: node linkType: hard @@ -1495,51 +1503,51 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.24.6 - resolution: "@babel/runtime@npm:7.24.6" + version: 7.24.7 + resolution: "@babel/runtime@npm:7.24.7" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/224ad205de33ea28979baaec89eea4c4d4e9482000dd87d15b97859365511cdd4d06517712504024f5d33a5fb9412f9b91c96f1d923974adf9359e1575cde049 + checksum: 10c0/b6fa3ec61a53402f3c1d75f4d808f48b35e0dfae0ec8e2bb5c6fc79fb95935da75766e0ca534d0f1c84871f6ae0d2ebdd950727cfadb745a2cdbef13faef5513 languageName: node linkType: hard -"@babel/template@npm:^7.24.6, @babel/template@npm:^7.3.3": - version: 7.24.6 - resolution: "@babel/template@npm:7.24.6" +"@babel/template@npm:^7.24.7, @babel/template@npm:^7.3.3": + version: 7.24.7 + resolution: "@babel/template@npm:7.24.7" dependencies: - "@babel/code-frame": "npm:^7.24.6" - "@babel/parser": "npm:^7.24.6" - "@babel/types": "npm:^7.24.6" - checksum: 10c0/a4d5805770de908b445f7cdcebfcb6eaa07b1ec9c7b78fd3f375a911b1522c249bddae6b96bc4aac24247cc603e3e6cffcf2fe50b4c929dfeb22de289b517525 + "@babel/code-frame": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/95b0b3ee80fcef685b7f4426f5713a855ea2cd5ac4da829b213f8fb5afe48a2a14683c2ea04d446dbc7f711c33c5cd4a965ef34dcbe5bc387c9e966b67877ae3 languageName: node linkType: hard -"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.6": - version: 7.24.6 - resolution: "@babel/traverse@npm:7.24.6" +"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/traverse@npm:7.24.7" dependencies: - "@babel/code-frame": "npm:^7.24.6" - "@babel/generator": "npm:^7.24.6" - "@babel/helper-environment-visitor": "npm:^7.24.6" - "@babel/helper-function-name": "npm:^7.24.6" - "@babel/helper-hoist-variables": "npm:^7.24.6" - "@babel/helper-split-export-declaration": "npm:^7.24.6" - "@babel/parser": "npm:^7.24.6" - "@babel/types": "npm:^7.24.6" + "@babel/code-frame": "npm:^7.24.7" + "@babel/generator": "npm:^7.24.7" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-function-name": "npm:^7.24.7" + "@babel/helper-hoist-variables": "npm:^7.24.7" + "@babel/helper-split-export-declaration": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10c0/39027d5fc7a241c6b71bb5872c2bdcec53743cd7ef3c151bbe6fd7cf874d15f4bc09e5d7e19e2f534b0eb2c115f5368553885fa4253aa1bc9441c6e5bf9efdaf + checksum: 10c0/a5135e589c3f1972b8877805f50a084a04865ccb1d68e5e1f3b94a8841b3485da4142e33413d8fd76bc0e6444531d3adf1f59f359c11ffac452b743d835068ab languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.6, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.24.6 - resolution: "@babel/types@npm:7.24.6" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.24.7 + resolution: "@babel/types@npm:7.24.7" dependencies: - "@babel/helper-string-parser": "npm:^7.24.6" - "@babel/helper-validator-identifier": "npm:^7.24.6" + "@babel/helper-string-parser": "npm:^7.24.7" + "@babel/helper-validator-identifier": "npm:^7.24.7" to-fast-properties: "npm:^2.0.0" - checksum: 10c0/1d94d92d97ef49030ad7f9e14cfccfeb70b1706dabcaa69037e659ec9d2c3178fb005d2088cce40d88dfc1306153d9157fe038a79ea2be92e5e6b99a59ef80cc + checksum: 10c0/d9ecbfc3eb2b05fb1e6eeea546836ac30d990f395ef3fe3f75ced777a222c3cfc4489492f72e0ce3d9a5a28860a1ce5f81e66b88cf5088909068b3ff4fab72c1 languageName: node linkType: hard From 578b0eae7d411a7b717adaf2ec280c4b1c33c265 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 6 Jun 2024 12:51:39 +0200 Subject: [PATCH 317/658] Fix /api/v1/timelines/link specs for glitch-soc default settings --- spec/requests/api/v1/timelines/link_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/requests/api/v1/timelines/link_spec.rb b/spec/requests/api/v1/timelines/link_spec.rb index a219c9bcdd..e964ee3da3 100644 --- a/spec/requests/api/v1/timelines/link_spec.rb +++ b/spec/requests/api/v1/timelines/link_spec.rb @@ -96,6 +96,10 @@ describe 'Link' do end context 'when the instance allows public preview' do + before do + Setting.timeline_preview = true + end + context 'with an authorized user' do it_behaves_like 'a successful request to the link timeline' end From 1ffc293b86fa373beada17fbe789b0e729781e07 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 6 Jun 2024 16:12:06 +0200 Subject: [PATCH 318/658] Add missing `moderation_warning` notification support to grouped notifications API (#30576) --- app/serializers/rest/notification_group_serializer.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/serializers/rest/notification_group_serializer.rb b/app/serializers/rest/notification_group_serializer.rb index 6c1d2465d2..05b51b07a5 100644 --- a/app/serializers/rest/notification_group_serializer.rb +++ b/app/serializers/rest/notification_group_serializer.rb @@ -11,6 +11,7 @@ class REST::NotificationGroupSerializer < ActiveModel::Serializer belongs_to :target_status, key: :status, if: :status_type?, serializer: REST::StatusSerializer belongs_to :report, if: :report_type?, serializer: REST::ReportSerializer belongs_to :account_relationship_severance_event, key: :event, if: :relationship_severance_event?, serializer: REST::AccountRelationshipSeveranceEventSerializer + belongs_to :account_warning, key: :moderation_warning, if: :moderation_warning_event?, serializer: REST::AccountWarningSerializer def status_type? [:favourite, :reblog, :status, :mention, :poll, :update].include?(object.type) @@ -24,6 +25,10 @@ class REST::NotificationGroupSerializer < ActiveModel::Serializer object.type == :severed_relationships end + def moderation_warning_event? + object.type == :moderation_warning + end + def page_min_id range = instance_options[:group_metadata][object.group_key] range.present? ? range[:min_id].to_s : object.notification.id.to_s From a662c6d1d82fbc0bb27a2d0a55c1a1c028c16dea Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 10:12:58 -0400 Subject: [PATCH 319/658] Use `sidekiq_inline` in admin/account_action model spec (#30565) --- spec/models/admin/account_action_spec.rb | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/spec/models/admin/account_action_spec.rb b/spec/models/admin/account_action_spec.rb index a9dcf352dc..e55db2f814 100644 --- a/spec/models/admin/account_action_spec.rb +++ b/spec/models/admin/account_action_spec.rb @@ -69,20 +69,22 @@ RSpec.describe Admin::AccountAction do end end - it 'sends notification, log the action, and closes other reports', :aggregate_failures do - other_report = Fabricate(:report, target_account: target_account) - - emails = [] - expect do - emails = capture_emails { subject } - end.to (change(Admin::ActionLog.where(action: type), :count).by 1) - .and(change { other_report.reload.action_taken? }.from(false).to(true)) + it 'sends email to target account user', :sidekiq_inline do + emails = capture_emails { subject } expect(emails).to contain_exactly( have_attributes( to: contain_exactly(target_account.user.email) ) ) + end + + it 'sends notification, log the action, and closes other reports', :aggregate_failures do + other_report = Fabricate(:report, target_account: target_account) + + expect { subject } + .to (change(Admin::ActionLog.where(action: type), :count).by 1) + .and(change { other_report.reload.action_taken? }.from(false).to(true)) expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(target_account.id, anything, 'AccountWarning', 'moderation_warning') end From 9b9b0e25b6839d162d96a19407611e9fc8192c81 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 10:14:33 -0400 Subject: [PATCH 320/658] Use `sidekiq_inline` in requests/api/v1/reports spec (#30564) --- spec/requests/api/v1/reports_spec.rb | 38 +++++++++++++--------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/spec/requests/api/v1/reports_spec.rb b/spec/requests/api/v1/reports_spec.rb index 94baf8cb98..9e8954a4c6 100644 --- a/spec/requests/api/v1/reports_spec.rb +++ b/spec/requests/api/v1/reports_spec.rb @@ -33,30 +33,28 @@ RSpec.describe 'Reports' do it_behaves_like 'forbidden for wrong scope', 'read read:reports' - it 'creates a report', :aggregate_failures do - perform_enqueued_jobs do - emails = capture_emails { subject } + it 'creates a report', :aggregate_failures, :sidekiq_inline do + emails = capture_emails { subject } - expect(response).to have_http_status(200) - expect(body_as_json).to match( - a_hash_including( - status_ids: [status.id.to_s], - category: category, - comment: 'reasons' - ) + expect(response).to have_http_status(200) + expect(body_as_json).to match( + a_hash_including( + status_ids: [status.id.to_s], + category: category, + comment: 'reasons' ) + ) - expect(target_account.targeted_reports).to_not be_empty - expect(target_account.targeted_reports.first.comment).to eq 'reasons' + expect(target_account.targeted_reports).to_not be_empty + expect(target_account.targeted_reports.first.comment).to eq 'reasons' - expect(emails.size) - .to eq(1) - expect(emails.first) - .to have_attributes( - to: contain_exactly(admin.email), - subject: eq(I18n.t('admin_mailer.new_report.subject', instance: Rails.configuration.x.local_domain, id: target_account.targeted_reports.first.id)) - ) - end + expect(emails.size) + .to eq(1) + expect(emails.first) + .to have_attributes( + to: contain_exactly(admin.email), + subject: eq(I18n.t('admin_mailer.new_report.subject', instance: Rails.configuration.x.local_domain, id: target_account.targeted_reports.first.id)) + ) end context 'when a status does not belong to the reported account' do From 07cc94e05fa89794714fb0434529657dfa992bca Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 10:19:22 -0400 Subject: [PATCH 321/658] Use `sidekiq_inline` in requests/api/v1/admin/account_actions spec (#30563) --- spec/requests/api/v1/admin/account_actions_spec.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/spec/requests/api/v1/admin/account_actions_spec.rb b/spec/requests/api/v1/admin/account_actions_spec.rb index 4167911a13..778658508e 100644 --- a/spec/requests/api/v1/admin/account_actions_spec.rb +++ b/spec/requests/api/v1/admin/account_actions_spec.rb @@ -10,10 +10,16 @@ RSpec.describe 'Account actions' do let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } shared_examples 'a successful notification delivery' do - it 'notifies the user about the action taken' do - expect { subject } - .to have_enqueued_job(ActionMailer::MailDeliveryJob) - .with('UserMailer', 'warning', 'deliver_now!', args: [User, AccountWarning]) + it 'notifies the user about the action taken', :sidekiq_inline do + emails = capture_emails { subject } + + expect(emails.size) + .to eq(1) + + expect(emails.first) + .to have_attributes( + to: contain_exactly(target_account.user.email) + ) end end From 04ebbe3077e7f39025428bfa596ada2d21be6dfb Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 10:19:37 -0400 Subject: [PATCH 322/658] Add `sidekiq_inline` to appeal service spec (#30562) --- spec/services/appeal_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/appeal_service_spec.rb b/spec/services/appeal_service_spec.rb index 10c0f148dc..3fad74db9d 100644 --- a/spec/services/appeal_service_spec.rb +++ b/spec/services/appeal_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe AppealService do +RSpec.describe AppealService, :sidekiq_inline do describe '#call' do let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } From 12823908bbc101dc3106ae0fd1b804ef164390ac Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 10:19:55 -0400 Subject: [PATCH 323/658] Adjust devcontainers welcome message to be less codespaces-specific (#30566) --- .devcontainer/welcome-message.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.devcontainer/welcome-message.txt b/.devcontainer/welcome-message.txt index 488cf92857..dbc19c910c 100644 --- a/.devcontainer/welcome-message.txt +++ b/.devcontainer/welcome-message.txt @@ -1,8 +1,7 @@ -👋 Welcome to "Mastodon" in GitHub Codespaces! +👋 Welcome to your Mastodon Dev Container! -🛠️ Your environment is fully setup with all the required software. +🛠️ Your environment is fully setup with all the required software. -🔍 To explore VS Code to its fullest, search using the Command Palette (Cmd/Ctrl + Shift + P or F1). - -📝 Edit away, run your app as usual, and we'll automatically make it available for you to access. +💥 Run `bin/dev` to start the application processes. +🥼 Run `RAILS_ENV=test bin/rails assets:precompile && RAILS_ENV=test bin/rspec` to run the test suite. From 94d8d1094f32fcdd2372533efde9ad0e129020fc Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 16:29:16 -0400 Subject: [PATCH 324/658] Provide richer failure information in `bin/setup` (#30581) --- bin/setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/setup b/bin/setup index 90700ac4f9..5d9622151d 100755 --- a/bin/setup +++ b/bin/setup @@ -5,7 +5,7 @@ require "fileutils" APP_ROOT = File.expand_path('..', __dir__) def system!(*args) - system(*args) || abort("\n== Command #{args} failed ==") + system(*args, exception: true) end FileUtils.chdir APP_ROOT do From 3495f0d9ba37ec10189ce1df60921f15554224d5 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 6 Jun 2024 16:33:28 -0400 Subject: [PATCH 325/658] Use corepack yarn in `bin/setup` (#30573) --- bin/setup | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/bin/setup b/bin/setup index 5d9622151d..93c6981d0b 100755 --- a/bin/setup +++ b/bin/setup @@ -13,17 +13,13 @@ FileUtils.chdir APP_ROOT do # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. - puts '== Installing dependencies ==' + puts "\n== Installing Ruby dependencies ==" system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') - # Install JavaScript dependencies - system! 'bin/yarn' - - # puts "\n== Copying sample files ==" - # unless File.exist?('config/database.yml') - # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' - # end + puts "\n== Installing JS dependencies ==" + system! 'corepack prepare' + system! 'bin/yarn install --immutable' puts "\n== Preparing database ==" system! 'bin/rails db:prepare' From ac3d761c7811d39534a829825c073e033b250867 Mon Sep 17 00:00:00 2001 From: Maya Friedrichs <_@maya.sh> Date: Fri, 7 Jun 2024 00:23:18 +0200 Subject: [PATCH 326/658] Remove gradient for collapsed toots This gradient is already set in `components.scss` with the new background --- .../flavours/glitch/styles/mastodon-light/diff.scss | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss index 119b0fc2a4..4040ee0fe0 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss @@ -513,13 +513,6 @@ html { } } -.status.collapsed .status__content::after { - background: linear-gradient( - rgba(darken($ui-base-color, 13%), 0), - rgba(darken($ui-base-color, 13%), 1) - ); -} - .drawer__inner__mastodon { background: $white url('data:image/svg+xml;utf8,') From 8041fa174b7c90c1c130342aede2d556e8f56e82 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 09:39:01 +0200 Subject: [PATCH 327/658] chore(deps): update opentelemetry-ruby (non-major) (#30555) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index ca32d0cca1..136d074d33 100644 --- a/Gemfile +++ b/Gemfile @@ -107,7 +107,7 @@ gem 'private_address_check', '~> 0.5' gem 'opentelemetry-api', '~> 1.2.5' group :opentelemetry do - gem 'opentelemetry-exporter-otlp', '~> 0.26.3', require: false + gem 'opentelemetry-exporter-otlp', '~> 0.27.0', require: false gem 'opentelemetry-instrumentation-active_job', '~> 0.7.1', require: false gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.20.1', require: false gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.21.2', require: false diff --git a/Gemfile.lock b/Gemfile.lock index bf5340a5b0..9ad9deacfb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -489,7 +489,7 @@ GEM opentelemetry-api (1.2.5) opentelemetry-common (0.20.1) opentelemetry-api (~> 1.0) - opentelemetry-exporter-otlp (0.26.3) + opentelemetry-exporter-otlp (0.27.0) google-protobuf (~> 3.14) googleapis-common-protos-types (~> 1.3) opentelemetry-api (~> 1.1) @@ -978,7 +978,7 @@ DEPENDENCIES omniauth-saml (~> 2.0) omniauth_openid_connect (~> 0.6.1) opentelemetry-api (~> 1.2.5) - opentelemetry-exporter-otlp (~> 0.26.3) + opentelemetry-exporter-otlp (~> 0.27.0) opentelemetry-instrumentation-active_job (~> 0.7.1) opentelemetry-instrumentation-active_model_serializers (~> 0.20.1) opentelemetry-instrumentation-concurrent_ruby (~> 0.21.2) From 1408733386219e1588c14d2fbf9f3c926513a5a3 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 7 Jun 2024 11:27:59 +0200 Subject: [PATCH 328/658] Fix Mastodon relying on ImageMagick even with `MASTODON_USE_LIBVIPS` (#30590) --- app/models/custom_emoji.rb | 2 +- spec/models/custom_emoji_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 1c9b443959..31ba91ad02 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -39,7 +39,7 @@ class CustomEmoji < ApplicationRecord has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode, inverse_of: false, dependent: nil - has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' } }, validate_media_type: false + has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp', file_geometry_parser: FastGeometryParser } }, validate_media_type: false, processors: [:lazy_thumbnail] normalizes :domain, with: ->(domain) { domain.downcase } diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb index a0903e5978..038d1d0c6c 100644 --- a/spec/models/custom_emoji_spec.rb +++ b/spec/models/custom_emoji_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe CustomEmoji do +RSpec.describe CustomEmoji, :paperclip_processing do describe '#search' do subject { described_class.search(search_term) } From ce07394ed5e9e5728db7da59910fbd83bc4a38ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 11:53:59 +0200 Subject: [PATCH 329/658] chore(deps): update dependency aws-sdk-s3 to v1.152.0 (#30572) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9ad9deacfb..1003e14426 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,17 +100,17 @@ GEM attr_required (1.0.2) awrence (1.2.1) aws-eventstream (1.3.0) - aws-partitions (1.929.0) - aws-sdk-core (3.196.1) + aws-partitions (1.940.0) + aws-sdk-core (3.197.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.81.0) - aws-sdk-core (~> 3, >= 3.193.0) + aws-sdk-kms (1.83.0) + aws-sdk-core (~> 3, >= 3.197.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.151.0) - aws-sdk-core (~> 3, >= 3.194.0) + aws-sdk-s3 (1.152.0) + aws-sdk-core (~> 3, >= 3.197.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) From c1b0c1a5e40c277b4b1f036fa882d90f0882cd67 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 11:59:30 +0200 Subject: [PATCH 330/658] New Crowdin Translations (automated) (#30586) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/la.json | 4 ++++ config/locales/doorkeeper.be.yml | 1 - config/locales/doorkeeper.bg.yml | 3 ++- config/locales/doorkeeper.br.yml | 1 + config/locales/doorkeeper.ca.yml | 3 ++- config/locales/doorkeeper.cs.yml | 1 - config/locales/doorkeeper.cy.yml | 1 - config/locales/doorkeeper.da.yml | 3 ++- config/locales/doorkeeper.de.yml | 3 ++- config/locales/doorkeeper.en-GB.yml | 1 - config/locales/doorkeeper.es-AR.yml | 3 ++- config/locales/doorkeeper.es-MX.yml | 3 ++- config/locales/doorkeeper.es.yml | 3 ++- config/locales/doorkeeper.eu.yml | 1 - config/locales/doorkeeper.fi.yml | 3 ++- config/locales/doorkeeper.fo.yml | 3 ++- config/locales/doorkeeper.fy.yml | 1 - config/locales/doorkeeper.gl.yml | 3 ++- config/locales/doorkeeper.he.yml | 3 ++- config/locales/doorkeeper.hu.yml | 3 ++- config/locales/doorkeeper.ia.yml | 1 - config/locales/doorkeeper.ie.yml | 1 - config/locales/doorkeeper.is.yml | 3 ++- config/locales/doorkeeper.it.yml | 3 ++- config/locales/doorkeeper.ja.yml | 1 - config/locales/doorkeeper.ko.yml | 3 ++- config/locales/doorkeeper.lt.yml | 1 - config/locales/doorkeeper.lv.yml | 1 - config/locales/doorkeeper.nl.yml | 3 ++- config/locales/doorkeeper.nn.yml | 1 - config/locales/doorkeeper.pl.yml | 3 ++- config/locales/doorkeeper.pt-BR.yml | 1 - config/locales/doorkeeper.pt-PT.yml | 3 ++- config/locales/doorkeeper.sl.yml | 1 - config/locales/doorkeeper.sq.yml | 3 ++- config/locales/doorkeeper.sr-Latn.yml | 3 ++- config/locales/doorkeeper.sr.yml | 3 ++- config/locales/doorkeeper.sv.yml | 1 - config/locales/doorkeeper.th.yml | 1 - config/locales/doorkeeper.tr.yml | 3 ++- config/locales/doorkeeper.uk.yml | 3 ++- config/locales/doorkeeper.vi.yml | 1 - config/locales/doorkeeper.zh-CN.yml | 3 ++- config/locales/doorkeeper.zh-HK.yml | 1 - config/locales/doorkeeper.zh-TW.yml | 3 ++- 45 files changed, 55 insertions(+), 43 deletions(-) diff --git a/app/javascript/mastodon/locales/la.json b/app/javascript/mastodon/locales/la.json index 48b2334008..a49ec94d72 100644 --- a/app/javascript/mastodon/locales/la.json +++ b/app/javascript/mastodon/locales/la.json @@ -32,6 +32,7 @@ "compose_form.direct_message_warning_learn_more": "Discere plura", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", + "compose_form.lock_disclaimer": "Tua ratio non est {clausa}. Quisquis te sequi potest ut visum accipiat nuntios tuos tantum pro sectatoribus.", "compose_form.lock_disclaimer.lock": "clausum", "compose_form.placeholder": "What is on your mind?", "compose_form.publish_form": "Barrire", @@ -91,6 +92,7 @@ "lightbox.next": "Secundum", "navigation_bar.domain_blocks": "Hidden domains", "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", + "notification.moderation_warning.action_none": "Tua ratiō monitum moderātiōnis accēpit.", "notification.reblog": "{name} boosted your status", "notifications.filter.all": "Omnia", "notifications.filter.polls": "Eventus electionis", @@ -107,6 +109,8 @@ "onboarding.steps.setup_profile.title": "Customize your profile", "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", "onboarding.steps.share_profile.title": "Share your profile", + "onboarding.tips.accounts_from_other_servers": "Scisne? Quoniam Mastodon dēcentālis est, nōnnulla profīlia quae invenīs in servīs aliīs quam tuōrum erunt hospitāta. Tamen cum eīs sine impedīmentō interāgere potes! Servus eōrum in alterā parte nōminis eōrum est!", + "onboarding.tips.migration": "Scisne? Sī sentīs {domain} tibi in futūrō nōn esse optimam servī ēlēctiōnem, ad alium servum Mastodon sine amittendō sectātōribus tuīs migrāre potes. Etiam tuum servum hospitārī potes!", "poll.closed": "Clausum", "poll.vote": "Eligere", "poll.voted": "Elegisti hoc responsum", diff --git a/config/locales/doorkeeper.be.yml b/config/locales/doorkeeper.be.yml index 5f0536c8da..748cbeafa1 100644 --- a/config/locales/doorkeeper.be.yml +++ b/config/locales/doorkeeper.be.yml @@ -174,7 +174,6 @@ be: read:filters: бачыць свае фільтры read:follows: бачыць свае падпіскі read:lists: бачыць свае спісы - read:me: чытайце толькі базавую інфармацыю аб сваім уліковым запісе read:mutes: бачыць свае ігнараванні read:notifications: бачыць свае абвесткі read:reports: бачыць свае скаргі diff --git a/config/locales/doorkeeper.bg.yml b/config/locales/doorkeeper.bg.yml index 7633156d78..dd53661827 100644 --- a/config/locales/doorkeeper.bg.yml +++ b/config/locales/doorkeeper.bg.yml @@ -135,6 +135,7 @@ bg: media: Прикачена мултимедия mutes: Заглушения notifications: Известия + profile: Вашият профил в Mastodon push: Изскачащи известия reports: Доклади search: Търсене @@ -165,6 +166,7 @@ bg: admin:write:reports: извършване на действия за модериране на докладвания crypto: употреба на цялостно шифроване follow: промяна на взаимоотношенията на акаунта + profile: само за четене на сведенията ви за профила на акаунта push: получаване на вашите изскачащи известия read: четене на всички данни от акаунта ви read:accounts: преглед на информация за акаунти @@ -174,7 +176,6 @@ bg: read:filters: преглед на вашите филтри read:follows: преглед на вашите последвания read:lists: преглед на вашите списъци - read:me: четене само на основните сведения за акаунта ви read:mutes: преглед на вашите заглушавания read:notifications: преглед на вашите известия read:reports: преглед на вашите докладвания diff --git a/config/locales/doorkeeper.br.yml b/config/locales/doorkeeper.br.yml index 7b7f4155bd..119d8681f0 100644 --- a/config/locales/doorkeeper.br.yml +++ b/config/locales/doorkeeper.br.yml @@ -104,6 +104,7 @@ br: lists: Listennoù media: Restroù media stag mutes: Kuzhet + profile: Ho profil Mastodon search: Klask statuses: Toudoù layouts: diff --git a/config/locales/doorkeeper.ca.yml b/config/locales/doorkeeper.ca.yml index 80827a87da..0323656dab 100644 --- a/config/locales/doorkeeper.ca.yml +++ b/config/locales/doorkeeper.ca.yml @@ -135,6 +135,7 @@ ca: media: Adjunts multimèdia mutes: Silenciats notifications: Notificacions + profile: El vostre perfil de Mastodon push: Notificacions push reports: Informes search: Cerca @@ -165,6 +166,7 @@ ca: admin:write:reports: fer l'acció de moderació en els informes crypto: usa xifrat d'extrem a extrem follow: modifica les relacions del compte + profile: només llegir la informació del perfil del vostre compte push: rebre notificacions push del teu compte read: llegir les dades del teu compte read:accounts: mira informació dels comptes @@ -174,7 +176,6 @@ ca: read:filters: mira els teus filtres read:follows: mira els teus seguiments read:lists: mira les teves llistes - read:me: llegir només la informació bàsica del vostre compte read:mutes: mira els teus silenciats read:notifications: mira les teves notificacions read:reports: mira els teus informes diff --git a/config/locales/doorkeeper.cs.yml b/config/locales/doorkeeper.cs.yml index 9719a9a246..be2a4d971a 100644 --- a/config/locales/doorkeeper.cs.yml +++ b/config/locales/doorkeeper.cs.yml @@ -174,7 +174,6 @@ cs: read:filters: vidět vaše filtry read:follows: vidět vaše sledování read:lists: vidět vaše seznamy - read:me: číst pouze základní informace vašeho účtu read:mutes: vidět vaše skrytí read:notifications: vidět vaše oznámení read:reports: vidět vaše hlášení diff --git a/config/locales/doorkeeper.cy.yml b/config/locales/doorkeeper.cy.yml index 88cd2b9d53..e79aa0359f 100644 --- a/config/locales/doorkeeper.cy.yml +++ b/config/locales/doorkeeper.cy.yml @@ -174,7 +174,6 @@ cy: read:filters: gweld eich hidlwyr read:follows: gweld eich dilynwyr read:lists: gweld eich rhestrau - read:me: darllen dim ond manylion elfennol eich cyfrif read:mutes: gweld eich anwybyddiadau read:notifications: gweld eich hysbysiadau read:reports: gweld eich adroddiadau diff --git a/config/locales/doorkeeper.da.yml b/config/locales/doorkeeper.da.yml index ed10e14e24..d462f43d3b 100644 --- a/config/locales/doorkeeper.da.yml +++ b/config/locales/doorkeeper.da.yml @@ -135,6 +135,7 @@ da: media: Medievedhæftninger mutes: Tavsgørelser notifications: Notifikationer + profile: Din Mastodon-profil push: Push-notifikationer reports: Anmeldelser search: Søgning @@ -165,6 +166,7 @@ da: admin:write:reports: udfør modereringshandlinger på anmeldelser crypto: benyt ende-til-ende kryptering follow: ændre kontorelationer + profile: læs kun kontoprofiloplysningerne push: modtag dine push-notifikationer read: læs alle dine kontodata read:accounts: se kontooplysninger @@ -174,7 +176,6 @@ da: read:filters: se dine filtre read:follows: se dine følger read:lists: se dine lister - read:me: læs kun kontoens basisoplysninger read:mutes: se dine tavsgørelser read:notifications: se dine notifikationer read:reports: se dine anmeldelser diff --git a/config/locales/doorkeeper.de.yml b/config/locales/doorkeeper.de.yml index 80d612255b..f303aa23a2 100644 --- a/config/locales/doorkeeper.de.yml +++ b/config/locales/doorkeeper.de.yml @@ -135,6 +135,7 @@ de: media: Medienanhänge mutes: Stummschaltungen notifications: Benachrichtigungen + profile: Dein Mastodon-Profil push: Push-Benachrichtigungen reports: Meldungen search: Suche @@ -165,6 +166,7 @@ de: admin:write:reports: Moderationsaktionen auf Meldungen ausführen crypto: Ende-zu-Ende-Verschlüsselung verwenden follow: Kontenbeziehungen verändern + profile: nur die Profilinformationen deines Kontos lesen push: deine Push-Benachrichtigungen erhalten read: all deine Daten lesen read:accounts: deine Kontoinformationen einsehen @@ -174,7 +176,6 @@ de: read:filters: deine Filter einsehen read:follows: sehen, wem du folgst read:lists: deine Listen sehen - read:me: nur deine grundlegenden Kontoinformationen lesen read:mutes: deine Stummschaltungen einsehen read:notifications: deine Benachrichtigungen sehen read:reports: deine Meldungen sehen diff --git a/config/locales/doorkeeper.en-GB.yml b/config/locales/doorkeeper.en-GB.yml index 2e537c5301..b3ceffb13f 100644 --- a/config/locales/doorkeeper.en-GB.yml +++ b/config/locales/doorkeeper.en-GB.yml @@ -174,7 +174,6 @@ en-GB: read:filters: see your filters read:follows: see your follows read:lists: see your lists - read:me: read only your account's basic information read:mutes: see your mutes read:notifications: see your notifications read:reports: see your reports diff --git a/config/locales/doorkeeper.es-AR.yml b/config/locales/doorkeeper.es-AR.yml index 47cfc451aa..0b04696b6a 100644 --- a/config/locales/doorkeeper.es-AR.yml +++ b/config/locales/doorkeeper.es-AR.yml @@ -135,6 +135,7 @@ es-AR: media: Adjuntos de medios mutes: Silenciados notifications: Notificaciones + profile: Tu perfil de Mastodon push: Notificaciones push reports: Denuncias search: Buscar @@ -165,6 +166,7 @@ es-AR: admin:write:reports: ejecutar acciones de moderación en denuncias crypto: usar cifrado de extremo a extremo follow: modificar relaciones de cuenta + profile: leer solo la información del perfil de tu cuenta push: recibir tus notificaciones push read: leer todos los datos de tu cuenta read:accounts: ver información de cuentas @@ -174,7 +176,6 @@ es-AR: read:filters: ver tus filtros read:follows: ver qué cuentas seguís read:lists: ver tus listas - read:me: leer solo la información básica de tu cuenta read:mutes: ver qué cuentas silenciaste read:notifications: ver tus notificaciones read:reports: ver tus denuncias diff --git a/config/locales/doorkeeper.es-MX.yml b/config/locales/doorkeeper.es-MX.yml index e56e0df3ba..54386c4c33 100644 --- a/config/locales/doorkeeper.es-MX.yml +++ b/config/locales/doorkeeper.es-MX.yml @@ -135,6 +135,7 @@ es-MX: media: Archivos adjuntos mutes: Silenciados notifications: Notificaciones + profile: Tu perfil de Mastodon push: Notificaciones push reports: Reportes search: Busqueda @@ -165,6 +166,7 @@ es-MX: admin:write:reports: realizar acciones de moderación en informes crypto: usar cifrado de extremo a extremo follow: seguir, bloquear, desbloquear y dejar de seguir cuentas + profile: leer sólo la información del perfil de tu cuenta push: recibir tus notificaciones push read: leer los datos de tu cuenta read:accounts: ver información de cuentas @@ -174,7 +176,6 @@ es-MX: read:filters: ver tus filtros read:follows: ver a quién sigues read:lists: ver tus listas - read:me: leer solo la información básica de tu cuenta read:mutes: ver a quién has silenciado read:notifications: ver tus notificaciones read:reports: ver tus informes diff --git a/config/locales/doorkeeper.es.yml b/config/locales/doorkeeper.es.yml index 44e165a215..9be036a1d4 100644 --- a/config/locales/doorkeeper.es.yml +++ b/config/locales/doorkeeper.es.yml @@ -135,6 +135,7 @@ es: media: Adjuntos multimedia mutes: Silenciados notifications: Notificaciones + profile: Tu perfil de Mastodon push: Notificaciones push reports: Informes search: Buscar @@ -165,6 +166,7 @@ es: admin:write:reports: realizar acciones de moderación en informes crypto: usar cifrado de extremo a extremo follow: seguir, bloquear, desbloquear y dejar de seguir cuentas + profile: leer sólo la información del perfil de tu cuenta push: recibir tus notificaciones push read: leer los datos de tu cuenta read:accounts: ver información de cuentas @@ -174,7 +176,6 @@ es: read:filters: ver tus filtros read:follows: ver a quién sigues read:lists: ver tus listas - read:me: leer solo la información básica de tu cuenta read:mutes: ver a quién has silenciado read:notifications: ver tus notificaciones read:reports: ver tus informes diff --git a/config/locales/doorkeeper.eu.yml b/config/locales/doorkeeper.eu.yml index 88a63f698b..e7963672fa 100644 --- a/config/locales/doorkeeper.eu.yml +++ b/config/locales/doorkeeper.eu.yml @@ -174,7 +174,6 @@ eu: read:filters: ikusi zure iragazkiak read:follows: ikusi zuk jarraitutakoak read:lists: ikusi zure zerrendak - read:me: irakurri soilik zure kontuaren oinarrizko informazioa read:mutes: ikusi zuk mutututakoak read:notifications: ikusi zure jakinarazpenak read:reports: ikusi zure salaketak diff --git a/config/locales/doorkeeper.fi.yml b/config/locales/doorkeeper.fi.yml index ae8963c76f..b028c10a82 100644 --- a/config/locales/doorkeeper.fi.yml +++ b/config/locales/doorkeeper.fi.yml @@ -135,6 +135,7 @@ fi: media: Medialiitteet mutes: Mykistykset notifications: Ilmoitukset + profile: Mastodon-profiilisi push: Puskuilmoitukset reports: Raportit search: Hae @@ -165,6 +166,7 @@ fi: admin:write:reports: suorita valvontatoimia raporteille crypto: käytä päästä päähän -salausta follow: muokkaa tilin suhteita + profile: lue vain tilisi profiilitietoja push: vastaanota puskuilmoituksiasi read: lue kaikkia tilin tietoja read:accounts: katso tilien tietoja @@ -174,7 +176,6 @@ fi: read:filters: katso suodattimiasi read:follows: katso seurattujasi read:lists: katso listojasi - read:me: lue tilisi perustietoja read:mutes: katso mykistyksiäsi read:notifications: katso ilmoituksiasi read:reports: katso raporttejasi diff --git a/config/locales/doorkeeper.fo.yml b/config/locales/doorkeeper.fo.yml index 4f5cc5a645..bd9457b620 100644 --- a/config/locales/doorkeeper.fo.yml +++ b/config/locales/doorkeeper.fo.yml @@ -135,6 +135,7 @@ fo: media: Viðfestir miðlar mutes: Doyvir notifications: Fráboðanir + profile: Tín Mastodon vangi push: Skumpifráboðanir reports: Meldingar search: Leita @@ -165,6 +166,7 @@ fo: admin:write:reports: útinna kjakleiðsluatgerðir á meldingum crypto: brúka enda-til-enda bronglan follow: broyta viðurskifti millum kontur + profile: les bara vangaupplýsingar av tíni kontu push: móttaka tínar skumpifráboðanir read: lesa allar dátur í tíni kontu read:accounts: vís kontuupplýsingar @@ -174,7 +176,6 @@ fo: read:filters: síggja tíni filtur read:follows: síggja hvørji tú fylgir read:lists: síggja tínar listar - read:me: les bara grundleggjandi upplýsingar av tínari kontu read:mutes: síggja tínar doyvingar read:notifications: síggja tínar fráboðanir read:reports: síggja tínar meldingar diff --git a/config/locales/doorkeeper.fy.yml b/config/locales/doorkeeper.fy.yml index 51f0055ff6..a43defc427 100644 --- a/config/locales/doorkeeper.fy.yml +++ b/config/locales/doorkeeper.fy.yml @@ -174,7 +174,6 @@ fy: read:filters: jo filters besjen read:follows: de accounts dy’tsto folgest besjen read:lists: jo listen besjen - read:me: allinnich de basisgegevens fan jo account lêze read:mutes: jo negearre brûkers besjen read:notifications: jo meldingen besjen read:reports: jo rapportearre berjochten besjen diff --git a/config/locales/doorkeeper.gl.yml b/config/locales/doorkeeper.gl.yml index d34c58decc..e86babd64c 100644 --- a/config/locales/doorkeeper.gl.yml +++ b/config/locales/doorkeeper.gl.yml @@ -135,6 +135,7 @@ gl: media: Anexos multimedia mutes: Acaladas notifications: Notificacións + profile: O teu perfil en Mastodon push: Notificacións Push reports: Denuncias search: Busca @@ -165,6 +166,7 @@ gl: admin:write:reports: executar accións de moderación nas denuncias crypto: usar cifrado de extremo-a-extremo follow: modificar as relacións da conta + profile: ler só a información de perfil da túa conta push: recibir notificacións push read: ler todos os datos da tua conta read:accounts: ver información das contas @@ -174,7 +176,6 @@ gl: read:filters: ver os filtros read:follows: ver a quen segues read:lists: ver as tuas listaxes - read:me: ler só a información básica da túa conta read:mutes: ver a quen tes acalado read:notifications: ver as notificacións read:reports: ver as túas denuncias diff --git a/config/locales/doorkeeper.he.yml b/config/locales/doorkeeper.he.yml index a6376fa4c1..7a664c486e 100644 --- a/config/locales/doorkeeper.he.yml +++ b/config/locales/doorkeeper.he.yml @@ -135,6 +135,7 @@ he: media: קבצי מדיה מצורפים mutes: השתקות notifications: התראות + profile: פרופיל המסטודון שלך push: התראות בדחיפה reports: דיווחים search: חיפוש @@ -165,6 +166,7 @@ he: admin:write:reports: ביצוע פעולות הנהלה על חשבונות crypto: שימוש בהצפנה מקצה לקצה follow: לעקוב, לחסום, להסיר חסימה ולהפסיק לעקוב אחרי חשבונות + profile: קריאה של פרטי הפרופיל שלך בלבד push: קבלת התראות בדחיפה read: לקרוא את המידע שבחשבונך read:accounts: צפיה במידע על חשבונות @@ -174,7 +176,6 @@ he: read:filters: צפייה במסננים read:follows: צפייה בנעקבים read:lists: צפיה ברשימותיך - read:me: לקריאה בלבד של פרטי חשבונך הבסיסיים read:mutes: צפיה במושתקיך read:notifications: צפיה בהתראותיך read:reports: צפיה בדוחותיך diff --git a/config/locales/doorkeeper.hu.yml b/config/locales/doorkeeper.hu.yml index 28ce283ffa..b2e51a47c1 100644 --- a/config/locales/doorkeeper.hu.yml +++ b/config/locales/doorkeeper.hu.yml @@ -135,6 +135,7 @@ hu: media: Médiamellékletek mutes: Némítások notifications: Értesítések + profile: Saját Mastodon-profil push: Push értesítések reports: Bejelentések search: Keresés @@ -165,6 +166,7 @@ hu: admin:write:reports: moderációs műveletek végzése bejelentéseken crypto: végpontok közti titkosítás használata follow: fiókkapcsolatok módosítása + profile: csak a saját profil alapvető adatainak olvasása push: push értesítések fogadása read: saját fiók adatainak olvasása read:accounts: fiók adatainak megtekintése @@ -174,7 +176,6 @@ hu: read:filters: szűrök megtekintése read:follows: követések megtekintése read:lists: listák megtekintése - read:me: csak a fiókod alapvető adatainak elolvasása read:mutes: némítások megtekintése read:notifications: értesítések megtekintése read:reports: bejelentések megtekintése diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index 40109a311c..5b99abb7b4 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -174,7 +174,6 @@ ia: read:filters: vider tu filtros read:follows: vider qui tu seque read:lists: vider tu listas - read:me: leger solmente le information basic de tu conto read:mutes: vider qui tu silentia read:notifications: vider tu notificationes read:reports: vider tu reportos diff --git a/config/locales/doorkeeper.ie.yml b/config/locales/doorkeeper.ie.yml index fc8132c926..0119f3573f 100644 --- a/config/locales/doorkeeper.ie.yml +++ b/config/locales/doorkeeper.ie.yml @@ -174,7 +174,6 @@ ie: read:filters: vider tui filtres read:follows: vider tui sequitores read:lists: vider tui listes - read:me: leer solmen li basic information de tui conto read:mutes: vider tui silentias read:notifications: vider tui notificationes read:reports: vider tui raportes diff --git a/config/locales/doorkeeper.is.yml b/config/locales/doorkeeper.is.yml index 995d507f5b..84a4d38954 100644 --- a/config/locales/doorkeeper.is.yml +++ b/config/locales/doorkeeper.is.yml @@ -135,6 +135,7 @@ is: media: Myndefnisviðhengi mutes: Þagganir notifications: Tilkynningar + profile: Mastodon notandasniðið þitt push: Ýti-tilkynningar reports: Kærur search: Leita @@ -165,6 +166,7 @@ is: admin:write:reports: framkvæma umsjónaraðgerðir á kærur crypto: nota enda-í-enda dulritun follow: breyta venslum aðgangs + profile: lesa einungis upplýsingar úr notandasniðinu þínu push: taka á móti ýti-tilkynningum til þín read: lesa öll gögn á notandaaðgangnum þínum read:accounts: sjá upplýsingar í notendaaðgöngum @@ -174,7 +176,6 @@ is: read:filters: skoða síurnar þínar read:follows: sjá hverjum þú fylgist með read:lists: skoða listana þína - read:me: lesa einungis grunnupplýsingar aðgangsins þíns read:mutes: skoða hverja þú þaggar read:notifications: sjá tilkynningarnar þínar read:reports: skoða skýrslurnar þína diff --git a/config/locales/doorkeeper.it.yml b/config/locales/doorkeeper.it.yml index f39f784665..f5df14deac 100644 --- a/config/locales/doorkeeper.it.yml +++ b/config/locales/doorkeeper.it.yml @@ -135,6 +135,7 @@ it: media: Allegati multimediali mutes: Silenziati notifications: Notifiche + profile: Il tuo profilo Mastodon push: Notifiche push reports: Segnalazioni search: Cerca @@ -165,6 +166,7 @@ it: admin:write:reports: eseguire azioni di moderazione sulle segnalazioni crypto: utilizzare la crittografia end-to-end follow: modifica le relazioni tra profili + profile: leggi solo le informazioni sul profilo del tuo account push: ricevere le tue notifiche push read: leggere tutti i dati del tuo profilo read:accounts: visualizzare le informazioni sui profili @@ -174,7 +176,6 @@ it: read:filters: visualizzare i tuoi filtri read:follows: visualizzare i tuoi seguiti read:lists: visualizzare i tuoi elenchi - read:me: leggi solo le informazioni di base del tuo account read:mutes: visualizzare i tuoi silenziamenti read:notifications: visualizzare le tue notifiche read:reports: visualizzare le tue segnalazioni diff --git a/config/locales/doorkeeper.ja.yml b/config/locales/doorkeeper.ja.yml index af61dbdcb7..62f2a3eb0a 100644 --- a/config/locales/doorkeeper.ja.yml +++ b/config/locales/doorkeeper.ja.yml @@ -174,7 +174,6 @@ ja: read:filters: フィルターの読み取り read:follows: フォローの読み取り read:lists: リストの読み取り - read:me: 自分のアカウントの基本的な情報の読み取りのみ read:mutes: ミュートの読み取り read:notifications: 通知の読み取り read:reports: 通報の読み取り diff --git a/config/locales/doorkeeper.ko.yml b/config/locales/doorkeeper.ko.yml index 12674cc125..3ab0698d51 100644 --- a/config/locales/doorkeeper.ko.yml +++ b/config/locales/doorkeeper.ko.yml @@ -135,6 +135,7 @@ ko: media: 첨부된 미디어 mutes: 뮤트 notifications: 알림 + profile: 내 마스토돈 프로필 push: 푸시 알림 reports: 신고 search: 검색 @@ -165,6 +166,7 @@ ko: admin:write:reports: 신고에 모더레이션 조치 취하기 crypto: 종단간 암호화 사용 follow: 계정 관계 수정 + profile: 내 계정의 프로필 정보만을 읽습니다 push: 푸시 알림 받기 read: 계정의 모든 데이터 읽기 read:accounts: 계정 정보 보기 @@ -174,7 +176,6 @@ ko: read:filters: 필터 보기 read:follows: 팔로우 보기 read:lists: 리스트 보기 - read:me: 내 계정의 기본 정보만을 읽습니다 read:mutes: 뮤트 보기 read:notifications: 알림 보기 read:reports: 신고 보기 diff --git a/config/locales/doorkeeper.lt.yml b/config/locales/doorkeeper.lt.yml index 82695d8ba6..5c2e4fd4e0 100644 --- a/config/locales/doorkeeper.lt.yml +++ b/config/locales/doorkeeper.lt.yml @@ -174,7 +174,6 @@ lt: read:filters: matyti tavo filtrus read:follows: matyti tavo sekimus read:lists: matyti tavo sąrašus - read:me: skaityti tik pagrindinę paskyros informaciją read:mutes: matyti tavo nutildymus read:notifications: matyti tavo pranešimus read:reports: matyti tavo ataskaitas diff --git a/config/locales/doorkeeper.lv.yml b/config/locales/doorkeeper.lv.yml index 2005ce3c79..5aa5daef3f 100644 --- a/config/locales/doorkeeper.lv.yml +++ b/config/locales/doorkeeper.lv.yml @@ -174,7 +174,6 @@ lv: read:filters: apskatīt savus filtrus read:follows: apskatīt savus sekotājus read:lists: apskatīt savus sarakstus - read:me: lasīt tikai Tava konta pamatinformāciju read:mutes: apskatīt savus apklusinātos read:notifications: apskatīt savus paziņojumus read:reports: apskatīt savus pārskatus diff --git a/config/locales/doorkeeper.nl.yml b/config/locales/doorkeeper.nl.yml index 9554c0ee6f..4115e0a17e 100644 --- a/config/locales/doorkeeper.nl.yml +++ b/config/locales/doorkeeper.nl.yml @@ -135,6 +135,7 @@ nl: media: Mediabijlagen mutes: Negeren notifications: Meldingen + profile: Jouw Mastodonprofiel push: Pushmeldingen reports: Rapportages search: Zoeken @@ -165,6 +166,7 @@ nl: admin:write:reports: moderatieacties op rapportages uitvoeren crypto: end-to-end-encryptie gebruiken follow: volgrelaties tussen accounts bewerken + profile: alleen de profielgegevens van jouw account lezen push: jouw pushmeldingen ontvangen read: alle gegevens van jouw account lezen read:accounts: informatie accounts bekijken @@ -174,7 +176,6 @@ nl: read:filters: jouw filters bekijken read:follows: de accounts die jij volgt bekijken read:lists: jouw lijsten bekijken - read:me: alleen de basisgegevens van jouw account lezen read:mutes: jouw genegeerde gebruikers bekijken read:notifications: jouw meldingen bekijken read:reports: jouw gerapporteerde berichten bekijken diff --git a/config/locales/doorkeeper.nn.yml b/config/locales/doorkeeper.nn.yml index ab0380c6fa..0e5d1ca455 100644 --- a/config/locales/doorkeeper.nn.yml +++ b/config/locales/doorkeeper.nn.yml @@ -174,7 +174,6 @@ nn: read:filters: sjå filtera dine read:follows: sjå fylgjarane dine read:lists: sjå listene dine - read:me: les berre kontoen din sin grunnleggjande informasjon read:mutes: sjå kven du har målbunde read:notifications: sjå varsla dine read:reports: sjå rapportane dine diff --git a/config/locales/doorkeeper.pl.yml b/config/locales/doorkeeper.pl.yml index eefca2de65..a18a86e979 100644 --- a/config/locales/doorkeeper.pl.yml +++ b/config/locales/doorkeeper.pl.yml @@ -135,6 +135,7 @@ pl: media: Załączniki multimedialne mutes: Wyciszenia notifications: Powiadomienia + profile: Twój profil push: Powiadomienia push reports: Zgłoszenia search: Szukaj @@ -165,6 +166,7 @@ pl: admin:write:reports: wykonaj działania moderacyjne na zgłoszeniach crypto: użyj szyfrowania end-to-end follow: możliwość zarządzania relacjami kont + profile: odczytaj tylko informacje o profilu push: otrzymywanie powiadomień push dla Twojego konta read: możliwość odczytu wszystkich danych konta read:accounts: dostęp do informacji o koncie @@ -174,7 +176,6 @@ pl: read:filters: dostęp do filtrów read:follows: dostęp do listy obserwowanych read:lists: dostęp do Twoich list - read:me: odczytaj tylko podstawowe informacje o koncie read:mutes: dostęp do listy wyciszonych read:notifications: możliwość odczytu powiadomień read:reports: dostęp do Twoich zgłoszeń diff --git a/config/locales/doorkeeper.pt-BR.yml b/config/locales/doorkeeper.pt-BR.yml index 150b4339e4..d7e9353b59 100644 --- a/config/locales/doorkeeper.pt-BR.yml +++ b/config/locales/doorkeeper.pt-BR.yml @@ -174,7 +174,6 @@ pt-BR: read:filters: ver seus filtros read:follows: ver quem você segue read:lists: ver suas listas - read:me: ler só as informações básicas da sua conta read:mutes: ver seus silenciados read:notifications: ver suas notificações read:reports: ver suas denúncias diff --git a/config/locales/doorkeeper.pt-PT.yml b/config/locales/doorkeeper.pt-PT.yml index 0457190cda..f03cee6b3a 100644 --- a/config/locales/doorkeeper.pt-PT.yml +++ b/config/locales/doorkeeper.pt-PT.yml @@ -135,6 +135,7 @@ pt-PT: media: Anexos de media mutes: Silenciados notifications: Notificações + profile: O seu perfil Mastodon push: Notificações push reports: Denúncias search: Pesquisa @@ -165,6 +166,7 @@ pt-PT: admin:write:reports: executar ações de moderação em denúncias crypto: usa encriptação ponta-a-ponta follow: siga, bloqueie, desbloqueie, e deixa de seguir contas + profile: apenas ler as informações do perfil da sua conta push: receber as suas notificações push read: tenha acesso aos dados da tua conta read:accounts: ver as informações da conta @@ -174,7 +176,6 @@ pt-PT: read:filters: ver os seus filtros read:follows: ver quem você segue read:lists: ver as suas listas - read:me: ler apenas as informações básicas da sua conta read:mutes: ver os utilizadores que silenciou read:notifications: ver as suas notificações read:reports: ver as suas denúncias diff --git a/config/locales/doorkeeper.sl.yml b/config/locales/doorkeeper.sl.yml index 55e00ff96d..a613308b28 100644 --- a/config/locales/doorkeeper.sl.yml +++ b/config/locales/doorkeeper.sl.yml @@ -174,7 +174,6 @@ sl: read:filters: oglejte si svoje filtre read:follows: oglejte si svoje sledilce read:lists: oglejte si svoje sezname - read:me: preberi le osnovne podatke računa read:mutes: oglejte si svoje utišane read:notifications: oglejte si svoja obvestila read:reports: oglejte si svoje prijave diff --git a/config/locales/doorkeeper.sq.yml b/config/locales/doorkeeper.sq.yml index 793819c597..de34154067 100644 --- a/config/locales/doorkeeper.sq.yml +++ b/config/locales/doorkeeper.sq.yml @@ -135,6 +135,7 @@ sq: media: Bashkëngjitje media mutes: Heshtime notifications: Njoftime + profile: Profili juaj Mastodon push: Njoftime Push reports: Raportime search: Kërkim @@ -165,6 +166,7 @@ sq: admin:write:reports: të kryejë veprime moderimi në raportime crypto: përdor fshehtëzim skaj-më-skaj follow: të ndryshojë marrëdhënie llogarish + profile: të lexojë vetëm hollësi profili llogarie tuaj push: të marrë njoftime push për ju read: të lexojë krejt të dhënat e llogarisë tuaj read:accounts: të shohë hollësi llogarish @@ -174,7 +176,6 @@ sq: read:filters: të shohë filtrat tuaj read:follows: të shohë ndjekësit tuaj read:lists: të shohë listat tuaja - read:me: të shohë vetëm hollësi elementare të llogarisë tuaj read:mutes: të shohë ç’keni heshtuar read:notifications: të shohë njoftimet tuaja read:reports: të shohë raportimet tuaja diff --git a/config/locales/doorkeeper.sr-Latn.yml b/config/locales/doorkeeper.sr-Latn.yml index 58ed5e8b68..6445353c1a 100644 --- a/config/locales/doorkeeper.sr-Latn.yml +++ b/config/locales/doorkeeper.sr-Latn.yml @@ -135,6 +135,7 @@ sr-Latn: media: Multimedijalni prilozi mutes: Ignorisani notifications: Obaveštenja + profile: Vaš Mastodon profil push: Prosleđena obaveštenja reports: Prijave search: Pretraga @@ -165,6 +166,7 @@ sr-Latn: admin:write:reports: vršenje moderatorskih aktivnosti nad izveštajima crypto: korišćenje end-to-end enkripcije follow: menja odnose naloga + profile: čita samo informacije o profilu vašeg naloga push: primanje prosleđenih obaveštenja read: čita podatke Vašeg naloga read:accounts: pogledaj informacije o nalozima @@ -174,7 +176,6 @@ sr-Latn: read:filters: pogledaj svoje filtere read:follows: pogledaj koga pratiš read:lists: pogledaj svoje liste - read:me: čita samo osnovne informacije o vašem nalogu read:mutes: pogledaj ignorisanja read:notifications: pogledaj svoja obaveštenja read:reports: pogledaj svoje prijave diff --git a/config/locales/doorkeeper.sr.yml b/config/locales/doorkeeper.sr.yml index f40a05e90d..feb0fec3e5 100644 --- a/config/locales/doorkeeper.sr.yml +++ b/config/locales/doorkeeper.sr.yml @@ -135,6 +135,7 @@ sr: media: Мултимедијални прилози mutes: Игнорисани notifications: Обавештења + profile: Ваш Mastodon профил push: Прослеђена обавештења reports: Пријаве search: Претрага @@ -165,6 +166,7 @@ sr: admin:write:reports: вршење модераторских активности над извештајима crypto: коришћење end-to-end енкрипције follow: мења односе налога + profile: чита само информације о профилу вашег налога push: примање прослеђених обавештења read: чита податке Вашег налога read:accounts: погледај информације о налозима @@ -174,7 +176,6 @@ sr: read:filters: погледај своје филтере read:follows: погледај кога пратиш read:lists: погледај своје листе - read:me: чита само основне информације о вашем налогу read:mutes: погледај игнорисања read:notifications: погледај своја обавештења read:reports: погледај своје пријаве diff --git a/config/locales/doorkeeper.sv.yml b/config/locales/doorkeeper.sv.yml index d336f08c56..f2c8bd34b8 100644 --- a/config/locales/doorkeeper.sv.yml +++ b/config/locales/doorkeeper.sv.yml @@ -174,7 +174,6 @@ sv: read:filters: se dina filter read:follows: se vem du följer read:lists: se dina listor - read:me: läs endast den grundläggande informationen för ditt konto read:mutes: se dina tystningar read:notifications: se dina notiser read:reports: se dina rapporter diff --git a/config/locales/doorkeeper.th.yml b/config/locales/doorkeeper.th.yml index 8a28566a0d..067e065588 100644 --- a/config/locales/doorkeeper.th.yml +++ b/config/locales/doorkeeper.th.yml @@ -174,7 +174,6 @@ th: read:filters: ดูตัวกรองของคุณ read:follows: ดูการติดตามของคุณ read:lists: ดูรายการของคุณ - read:me: อ่านเฉพาะข้อมูลพื้นฐานของบัญชีของคุณเท่านั้น read:mutes: ดูการซ่อนของคุณ read:notifications: ดูการแจ้งเตือนของคุณ read:reports: ดูรายงานของคุณ diff --git a/config/locales/doorkeeper.tr.yml b/config/locales/doorkeeper.tr.yml index f5ebbc5fd8..330449b1b5 100644 --- a/config/locales/doorkeeper.tr.yml +++ b/config/locales/doorkeeper.tr.yml @@ -135,6 +135,7 @@ tr: media: Medya ekleri mutes: Sessize alınanlar notifications: Bildirimler + profile: Mastodon profiliniz push: Anlık bildirimler reports: Şikayetler search: Arama @@ -165,6 +166,7 @@ tr: admin:write:reports: raporlarda denetleme eylemleri gerçekleştirin crypto: uçtan uca şifreleme kullan follow: hesap ilişkilerini değiştirin + profile: hesabınızın sadece profil bilgilerini okuma push: anlık bildirimlerizi alın read: hesabınızın tüm verilerini okuyun read:accounts: hesap bilgilerini görün @@ -174,7 +176,6 @@ tr: read:filters: süzgeçlerinizi görün read:follows: takip ettiklerinizi görün read:lists: listelerinizi görün - read:me: hesabınızın sadece temel bilgilerini okuma read:mutes: sessize aldıklarınızı görün read:notifications: bildirimlerinizi görün read:reports: raporlarınızı görün diff --git a/config/locales/doorkeeper.uk.yml b/config/locales/doorkeeper.uk.yml index ac7fbbe15d..ca54fcb65a 100644 --- a/config/locales/doorkeeper.uk.yml +++ b/config/locales/doorkeeper.uk.yml @@ -135,6 +135,7 @@ uk: media: Мультимедійні вкладення mutes: Нехтувані notifications: Сповіщення + profile: Ваш профіль Mastodon push: Push-сповіщення reports: Скарги search: Пошук @@ -171,6 +172,7 @@ uk: admin:write:reports: модерувати скарги crypto: використовувати наскрізне шифрування follow: змінювати стосунки облікового запису + profile: читати лише інформацію профілю вашого облікового запису push: отримувати Ваші Push-повідомлення read: читати усі дані вашого облікового запису read:accounts: бачити інформацію про облікові записи @@ -180,7 +182,6 @@ uk: read:filters: бачити Ваші фільтри read:follows: бачити Ваші підписки read:lists: бачити Ваші списки - read:me: читайте лише основну інформацію вашого облікового запису read:mutes: бачити ваші нехтування read:notifications: бачити Ваші сповіщення read:reports: бачити Ваші скарги diff --git a/config/locales/doorkeeper.vi.yml b/config/locales/doorkeeper.vi.yml index 624db9aff7..7f1c5430ed 100644 --- a/config/locales/doorkeeper.vi.yml +++ b/config/locales/doorkeeper.vi.yml @@ -174,7 +174,6 @@ vi: read:filters: xem bộ lọc read:follows: xem những người theo dõi read:lists: xem danh sách - read:me: chỉ đọc thông tin cơ bản tài khoản read:mutes: xem những người đã ẩn read:notifications: xem thông báo read:reports: xem báo cáo của bạn diff --git a/config/locales/doorkeeper.zh-CN.yml b/config/locales/doorkeeper.zh-CN.yml index 73f1f9725c..18477bc845 100644 --- a/config/locales/doorkeeper.zh-CN.yml +++ b/config/locales/doorkeeper.zh-CN.yml @@ -135,6 +135,7 @@ zh-CN: media: 媒体文件 mutes: 已被隐藏的 notifications: 通知 + profile: 你的 Mastodon 个人资料 push: 推送通知 reports: 举报 search: 搜索 @@ -165,6 +166,7 @@ zh-CN: admin:write:reports: 对举报执行管理操作 crypto: 使用端到端加密 follow: 关注或屏蔽用户 + profile: 仅读取你账户中的个人资料信息 push: 接收你的账户的推送通知 read: 读取你的账户数据 read:accounts: 查看账号信息 @@ -174,7 +176,6 @@ zh-CN: read:filters: 查看你的过滤器 read:follows: 查看你的关注 read:lists: 查看你的列表 - read:me: 只读取你账户的基本信息 read:mutes: 查看你的隐藏列表 read:notifications: 查看你的通知 read:reports: 查看你的举报 diff --git a/config/locales/doorkeeper.zh-HK.yml b/config/locales/doorkeeper.zh-HK.yml index 76d13a74a5..79629b12fe 100644 --- a/config/locales/doorkeeper.zh-HK.yml +++ b/config/locales/doorkeeper.zh-HK.yml @@ -174,7 +174,6 @@ zh-HK: read:filters: 檢視你的過濾條件 read:follows: 檢視你關注的人 read:lists: 檢視你的清單 - read:me: 僅讀取帳號的基本資訊 read:mutes: 檢視被你靜音的人 read:notifications: 檢視你的通知 read:reports: 檢視你的檢舉 diff --git a/config/locales/doorkeeper.zh-TW.yml b/config/locales/doorkeeper.zh-TW.yml index 86827a7122..d12651a648 100644 --- a/config/locales/doorkeeper.zh-TW.yml +++ b/config/locales/doorkeeper.zh-TW.yml @@ -135,6 +135,7 @@ zh-TW: media: 多媒體附加檔案 mutes: 靜音 notifications: 通知 + profile: 您 Mastodon 個人檔案 push: 推播通知 reports: 檢舉報告 search: 搜尋 @@ -165,6 +166,7 @@ zh-TW: admin:write:reports: 對報告進行管理動作 crypto: 使用端到端加密 follow: 修改帳號關係 + profile: 僅讀取您的帳號個人檔案資訊 push: 接收帳號的推播通知 read: 讀取您所有的帳號資料 read:accounts: 檢視帳號資訊 @@ -174,7 +176,6 @@ zh-TW: read:filters: 檢視您的過濾條件 read:follows: 檢視您跟隨之使用者 read:lists: 檢視您的列表 - read:me: 僅讀取您的帳號基本資訊 read:mutes: 檢視您靜音的人 read:notifications: 檢視您的通知 read:reports: 檢視您的檢舉 From 3dfc7267e20aab8e5e72adffbf1ef4773811c068 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 7 Jun 2024 06:00:27 -0400 Subject: [PATCH 331/658] Rename deprecated config option to `enable_reloading` in dev env (#30577) --- config/environments/development.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index a3254125c0..cc601bde3f 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -8,7 +8,7 @@ Rails.application.configure do # In the development environment your application's code is reloaded any time # it changes. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. - config.cache_classes = false + config.enable_reloading = true # Do not eager load code on boot. config.eager_load = false From a5e3b814a207365edfcf1f625c1594774f936ab4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 7 Jun 2024 06:00:51 -0400 Subject: [PATCH 332/658] Remove Status/ivar/shapes regression check from test env (#30580) --- config/environments/test.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index 49b0c1f303..716bf8d31f 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -61,12 +61,6 @@ Rails.application.configure do config.i18n.default_locale = :en config.i18n.fallbacks = true - config.to_prepare do - # Force Status to always be SHAPE_TOO_COMPLEX - # Ref: https://github.com/mastodon/mastodon/issues/23644 - 10.times { |i| Status.allocate.instance_variable_set(:"@ivar_#{i}", nil) } - end - # Tell Active Support which deprecation messages to disallow. config.active_support.disallowed_deprecation_warnings = [] From 3d058f898a8e029b8e0d007f4528b2ae878b8fc4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:37:50 +0200 Subject: [PATCH 333/658] chore(deps): update dependency rubocop-rspec to v2.31.0 (#30588) 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 1003e14426..8ff990260b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -751,7 +751,7 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (2.30.0) + rubocop-rspec (2.31.0) rubocop (~> 1.40) rubocop-capybara (~> 2.17) rubocop-factory_bot (~> 2.22) From bc01b328a10cdf93e098fd016feb26b01cc58bdb Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 7 Jun 2024 08:21:38 -0400 Subject: [PATCH 334/658] Dont include peer dirs in devcontainer compose config (#30592) --- .devcontainer/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 85f9eb22cc..4d6eb3c487 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -5,7 +5,7 @@ services: context: . dockerfile: Dockerfile volumes: - - ../..:/workspaces:cached + - ..:/workspaces/mastodon:cached environment: RAILS_ENV: development NODE_ENV: development From 299ae9bf922401751dc2a4dd50739a0391e0863a Mon Sep 17 00:00:00 2001 From: Victor Dyotte Date: Fri, 7 Jun 2024 08:29:30 -0400 Subject: [PATCH 335/658] Add `S3_KEY_PREFIX` environment variable (#30181) --- config/initializers/paperclip.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index 5b9365a530..0be78b99f9 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -3,6 +3,8 @@ Paperclip::DataUriAdapter.register Paperclip::ResponseWithLimitAdapter.register +PATH = ':prefix_url:class/:attachment/:id_partition/:style/:filename' + Paperclip.interpolates :filename do |attachment, style| if style == :original attachment.original_filename @@ -29,7 +31,7 @@ end Paperclip::Attachment.default_options.merge!( use_timestamp: false, - path: ':prefix_url:class/:attachment/:id_partition/:style/:filename', + path: PATH, storage: :fog ) @@ -40,6 +42,8 @@ if ENV['S3_ENABLED'] == 'true' s3_protocol = ENV.fetch('S3_PROTOCOL') { 'https' } s3_hostname = ENV.fetch('S3_HOSTNAME') { "s3-#{s3_region}.amazonaws.com" } + Paperclip::Attachment.default_options[:path] = ENV.fetch('S3_KEY_PREFIX') + "/#{PATH}" if ENV.has_key?('S3_KEY_PREFIX') + Paperclip::Attachment.default_options.merge!( storage: :s3, s3_protocol: s3_protocol, @@ -159,7 +163,7 @@ else Paperclip::Attachment.default_options.merge!( storage: :filesystem, path: File.join(ENV.fetch('PAPERCLIP_ROOT_PATH', File.join(':rails_root', 'public', 'system')), ':prefix_path:class', ':attachment', ':id_partition', ':style', ':filename'), - url: "#{ENV.fetch('PAPERCLIP_ROOT_URL', '/system')}/:prefix_url:class/:attachment/:id_partition/:style/:filename" + url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + "/#{PATH}" ) end From 37e4d96b70b46fb0994af23eefd6a77498895ba3 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 7 Jun 2024 08:39:53 -0400 Subject: [PATCH 336/658] Restore `verbose` option to media remove cli (#30536) --- lib/mastodon/cli/media.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/mastodon/cli/media.rb b/lib/mastodon/cli/media.rb index 509d11a819..123973d195 100644 --- a/lib/mastodon/cli/media.rb +++ b/lib/mastodon/cli/media.rb @@ -13,6 +13,7 @@ module Mastodon::CLI option :remove_headers, type: :boolean, default: false option :include_follows, type: :boolean, default: false option :concurrency, type: :numeric, default: 5, aliases: [:c] + option :verbose, type: :boolean, default: false, aliases: [:v] option :dry_run, type: :boolean, default: false desc 'remove', 'Remove remote media files, headers or avatars' long_desc <<-DESC From 9e9613b2864062ce4174ae02db3f94629ebdca0e Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 7 Jun 2024 15:45:11 +0200 Subject: [PATCH 337/658] Fix `mentions.account_id` and `mentions.status_id` not having `NOT NULL` database constraints (#30591) --- app/models/mention.rb | 4 ++-- ...093446_change_mention_status_id_non_nullable.rb | 7 +++++++ ...lidate_change_mention_status_id_non_nullable.rb | 14 ++++++++++++++ ...94603_change_mention_account_id_non_nullable.rb | 7 +++++++ ...idate_change_mention_account_id_non_nullable.rb | 14 ++++++++++++++ db/schema.rb | 6 +++--- 6 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20240607093446_change_mention_status_id_non_nullable.rb create mode 100644 db/migrate/20240607093954_validate_change_mention_status_id_non_nullable.rb create mode 100644 db/migrate/20240607094603_change_mention_account_id_non_nullable.rb create mode 100644 db/migrate/20240607094856_validate_change_mention_account_id_non_nullable.rb diff --git a/app/models/mention.rb b/app/models/mention.rb index 2348b2905c..af9bb7378b 100644 --- a/app/models/mention.rb +++ b/app/models/mention.rb @@ -5,10 +5,10 @@ # Table name: mentions # # id :bigint(8) not null, primary key -# status_id :bigint(8) +# status_id :bigint(8) not null # created_at :datetime not null # updated_at :datetime not null -# account_id :bigint(8) +# account_id :bigint(8) not null # silent :boolean default(FALSE), not null # diff --git a/db/migrate/20240607093446_change_mention_status_id_non_nullable.rb b/db/migrate/20240607093446_change_mention_status_id_non_nullable.rb new file mode 100644 index 0000000000..b6ee4d318f --- /dev/null +++ b/db/migrate/20240607093446_change_mention_status_id_non_nullable.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class ChangeMentionStatusIdNonNullable < ActiveRecord::Migration[7.1] + def change + add_check_constraint :mentions, 'status_id IS NOT NULL', name: 'mentions_status_id_null', validate: false + end +end diff --git a/db/migrate/20240607093954_validate_change_mention_status_id_non_nullable.rb b/db/migrate/20240607093954_validate_change_mention_status_id_non_nullable.rb new file mode 100644 index 0000000000..bd3d9a33a6 --- /dev/null +++ b/db/migrate/20240607093954_validate_change_mention_status_id_non_nullable.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class ValidateChangeMentionStatusIdNonNullable < ActiveRecord::Migration[7.1] + def up + validate_check_constraint :mentions, name: 'mentions_status_id_null' + change_column_null :mentions, :status_id, false + remove_check_constraint :mentions, name: 'mentions_status_id_null' + end + + def down + add_check_constraint :mentions, 'status_id IS NOT NULL', name: 'mentions_status_id_null', validate: false + change_column_null :mentions, :status_id, true + end +end diff --git a/db/migrate/20240607094603_change_mention_account_id_non_nullable.rb b/db/migrate/20240607094603_change_mention_account_id_non_nullable.rb new file mode 100644 index 0000000000..72d7bf2447 --- /dev/null +++ b/db/migrate/20240607094603_change_mention_account_id_non_nullable.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class ChangeMentionAccountIdNonNullable < ActiveRecord::Migration[7.1] + def change + add_check_constraint :mentions, 'account_id IS NOT NULL', name: 'mentions_account_id_null', validate: false + end +end diff --git a/db/migrate/20240607094856_validate_change_mention_account_id_non_nullable.rb b/db/migrate/20240607094856_validate_change_mention_account_id_non_nullable.rb new file mode 100644 index 0000000000..1125dffb39 --- /dev/null +++ b/db/migrate/20240607094856_validate_change_mention_account_id_non_nullable.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class ValidateChangeMentionAccountIdNonNullable < ActiveRecord::Migration[7.1] + def up + validate_check_constraint :mentions, name: 'mentions_account_id_null' + change_column_null :mentions, :account_id, false + remove_check_constraint :mentions, name: 'mentions_account_id_null' + end + + def down + add_check_constraint :mentions, 'account_id IS NOT NULL', name: 'mentions_account_id_null', validate: false + change_column_null :mentions, :account_id, true + end +end diff --git a/db/schema.rb b/db/schema.rb index ce2951608b..5f8c7e693f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_03_195202) do +ActiveRecord::Schema[7.1].define(version: 2024_06_07_094856) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -661,10 +661,10 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_03_195202) do end create_table "mentions", force: :cascade do |t| - t.bigint "status_id" + t.bigint "status_id", null: false t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false - t.bigint "account_id" + t.bigint "account_id", null: false t.boolean "silent", default: false, null: false t.index ["account_id", "status_id"], name: "index_mentions_on_account_id_and_status_id", unique: true t.index ["status_id"], name: "index_mentions_on_status_id" From 773283ffb9d227d7768d3c32a1a4bf556f0fb0a3 Mon Sep 17 00:00:00 2001 From: Isa S Date: Fri, 7 Jun 2024 15:54:55 +0200 Subject: [PATCH 338/658] Make S3's retry limit a ENV variable (#23215) --- config/initializers/paperclip.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index 0be78b99f9..e9e3c78cfa 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -68,7 +68,7 @@ if ENV['S3_ENABLED'] == 'true' http_open_timeout: ENV.fetch('S3_OPEN_TIMEOUT') { '5' }.to_i, http_read_timeout: ENV.fetch('S3_READ_TIMEOUT') { '5' }.to_i, http_idle_timeout: 5, - retry_limit: 0, + retry_limit: ENV.fetch('S3_RETRY_LIMIT'){ '0' }.to_i, } ) From 4f6cc547d0a7828d036d22f320b9c078e492a9c4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 7 Jun 2024 09:55:55 -0400 Subject: [PATCH 339/658] Align root/vscode user dynamic for codespaces with non-codespaces config (#30593) --- .devcontainer/Dockerfile | 4 ++-- .devcontainer/codespaces/devcontainer.json | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 9d8fa2702d..a0dc24ee84 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -5,7 +5,7 @@ FROM mcr.microsoft.com/devcontainers/ruby:1-3.3-bookworm # RUN gem install rails webdrivers ARG NODE_VERSION="20" -RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1" +RUN . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1 # [Optional] Uncomment this section to install additional OS packages. RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ @@ -15,6 +15,6 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ RUN gem install foreman # [Optional] Uncomment this line to install global node packages. -RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && corepack enable" 2>&1 +RUN . /usr/local/share/nvm/nvm.sh && corepack enable 2>&1 COPY welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt diff --git a/.devcontainer/codespaces/devcontainer.json b/.devcontainer/codespaces/devcontainer.json index 6736734e60..c14d2c529a 100644 --- a/.devcontainer/codespaces/devcontainer.json +++ b/.devcontainer/codespaces/devcontainer.json @@ -23,6 +23,8 @@ } }, + "remoteUser": "root", + "otherPortsAttributes": { "onAutoForward": "silent" }, From 80cd001e0aa876b690c6862e2f9cbb945074f2ff Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 7 Jun 2024 16:32:29 +0200 Subject: [PATCH 340/658] Fix linting issue (#30595) --- config/initializers/paperclip.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index e9e3c78cfa..070d250bf3 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -68,7 +68,7 @@ if ENV['S3_ENABLED'] == 'true' http_open_timeout: ENV.fetch('S3_OPEN_TIMEOUT') { '5' }.to_i, http_read_timeout: ENV.fetch('S3_READ_TIMEOUT') { '5' }.to_i, http_idle_timeout: 5, - retry_limit: ENV.fetch('S3_RETRY_LIMIT'){ '0' }.to_i, + retry_limit: ENV.fetch('S3_RETRY_LIMIT') { '0' }.to_i, } ) From 82be5d033f9a5e9335d4efee6008439c7770f102 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 7 Jun 2024 17:39:41 +0200 Subject: [PATCH 341/658] Improve handling of libvips failures (#30597) --- lib/paperclip/blurhash_transcoder.rb | 2 ++ lib/paperclip/color_extractor.rb | 2 ++ lib/paperclip/vips_lazy_thumbnail.rb | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/paperclip/blurhash_transcoder.rb b/lib/paperclip/blurhash_transcoder.rb index e9cecef50c..150275bc9e 100644 --- a/lib/paperclip/blurhash_transcoder.rb +++ b/lib/paperclip/blurhash_transcoder.rb @@ -12,6 +12,8 @@ module Paperclip attachment.instance.blurhash = Blurhash.encode(width, height, data, **(options[:blurhash] || {})) @file + rescue Vips::Error => e + raise Paperclip::Error, "Error while generating blurhash for #{@basename}: #{e}" end private diff --git a/lib/paperclip/color_extractor.rb b/lib/paperclip/color_extractor.rb index b5992f90bc..0f168d233b 100644 --- a/lib/paperclip/color_extractor.rb +++ b/lib/paperclip/color_extractor.rb @@ -69,6 +69,8 @@ module Paperclip attachment.instance.file.instance_write(:meta, (attachment.instance.file.instance_read(:meta) || {}).merge(meta)) @file + rescue Vips::Error => e + raise Paperclip::Error, "Error while extracting colors for #{@basename}: #{e}" end private diff --git a/lib/paperclip/vips_lazy_thumbnail.rb b/lib/paperclip/vips_lazy_thumbnail.rb index 06d99bf79d..4764b04af8 100644 --- a/lib/paperclip/vips_lazy_thumbnail.rb +++ b/lib/paperclip/vips_lazy_thumbnail.rb @@ -68,7 +68,7 @@ module Paperclip end dst - rescue Terrapin::ExitStatusError => e + rescue Vips::Error, Terrapin::ExitStatusError => e raise Paperclip::Error, "Error while optimizing #{@basename}: #{e}" rescue Terrapin::CommandNotFoundError raise Paperclip::Errors::CommandNotFoundError, 'Could not run the `ffmpeg` command. Please install ffmpeg.' From 496c10542bd39ca86a85d4de81778c134ea4383c Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 7 Jun 2024 19:42:43 +0200 Subject: [PATCH 342/658] Fix division by zero on some video/GIF files (#30600) --- app/lib/video_metadata_extractor.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/lib/video_metadata_extractor.rb b/app/lib/video_metadata_extractor.rb index df5409375f..2155766251 100644 --- a/app/lib/video_metadata_extractor.rb +++ b/app/lib/video_metadata_extractor.rb @@ -41,8 +41,8 @@ class VideoMetadataExtractor @colorspace = video_stream[:pix_fmt] @width = video_stream[:width] @height = video_stream[:height] - @frame_rate = video_stream[:avg_frame_rate] == '0/0' ? nil : Rational(video_stream[:avg_frame_rate]) - @r_frame_rate = video_stream[:r_frame_rate] == '0/0' ? nil : Rational(video_stream[:r_frame_rate]) + @frame_rate = parse_framerate(video_stream[:avg_frame_rate]) + @r_frame_rate = parse_framerate(video_stream[:r_frame_rate]) # For some video streams the frame_rate reported by `ffprobe` will be 0/0, but for these streams we # should use `r_frame_rate` instead. Video screencast generated by Gnome Screencast have this issue. @frame_rate ||= @r_frame_rate @@ -55,4 +55,10 @@ class VideoMetadataExtractor @invalid = true if @metadata.key?(:error) end + + def parse_framerate(raw) + Rational(raw) + rescue ZeroDivisionError + nil + end end From 521b43393350be16fbd1aa003607480c2442f3eb Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 7 Jun 2024 16:18:02 -0400 Subject: [PATCH 343/658] Doc updates for Docker/devcontainers/codespace (#30582) --- .devcontainer/Dockerfile | 17 +++----- .devcontainer/codespaces/devcontainer.json | 2 +- .../{docker-compose.yml => compose.yaml} | 0 .devcontainer/devcontainer.json | 2 +- README.md | 43 +++++++++++++------ 5 files changed, 38 insertions(+), 26 deletions(-) rename .devcontainer/{docker-compose.yml => compose.yaml} (100%) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a0dc24ee84..113dd71880 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,20 +1,17 @@ # For details, see https://github.com/devcontainers/images/tree/main/src/ruby FROM mcr.microsoft.com/devcontainers/ruby:1-3.3-bookworm -# Install Rails -# RUN gem install rails webdrivers - +# Update existing node version, keep in sync with .nvmrc ARG NODE_VERSION="20" RUN . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1 -# [Optional] Uncomment this section to install additional OS packages. -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg imagemagick libvips42 libpam-dev +# Install additional OS packages +RUN apt-get update && \ + export DEBIAN_FRONTEND=noninteractive && \ + apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg imagemagick libvips42 libpam-dev -# [Optional] Uncomment this line to install additional gems. -RUN gem install foreman - -# [Optional] Uncomment this line to install global node packages. +# Install global node packages RUN . /usr/local/share/nvm/nvm.sh && corepack enable 2>&1 +# Move welcome message to where VS Code expects it COPY welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt diff --git a/.devcontainer/codespaces/devcontainer.json b/.devcontainer/codespaces/devcontainer.json index c14d2c529a..d2358657f6 100644 --- a/.devcontainer/codespaces/devcontainer.json +++ b/.devcontainer/codespaces/devcontainer.json @@ -1,6 +1,6 @@ { "name": "Mastodon on GitHub Codespaces", - "dockerComposeFile": "../docker-compose.yml", + "dockerComposeFile": "../compose.yaml", "service": "app", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/compose.yaml similarity index 100% rename from .devcontainer/docker-compose.yml rename to .devcontainer/compose.yaml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4a9cf11cc2..fb88f7801f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "Mastodon on local machine", - "dockerComposeFile": "docker-compose.yml", + "dockerComposeFile": "compose.yaml", "service": "app", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", diff --git a/README.md b/README.md index 3773b647fe..f807120c1e 100644 --- a/README.md +++ b/README.md @@ -102,26 +102,35 @@ To set up **MacOS** for native development, complete the following steps: ### Docker For production hosting and deployment with **Docker**, use the `Dockerfile` and -`docker-compose.yml` in the project root directory. To create a local -development environment with **Docker**, complete the following steps: +`docker-compose.yml` in the project root directory. -- Install Docker Desktop -- Run `docker compose -f .devcontainer/docker-compose.yml up -d` -- Run `docker compose -f .devcontainer/docker-compose.yml exec app bin/setup` -- Finally, run `docker compose -f .devcontainer/docker-compose.yml exec app bin/dev` +For local development, install and launch [Docker], and run: -If you are using an IDE with [support for the Development Container specification](https://containers.dev/supporting), it will run the above `docker compose` commands automatically. For **Visual Studio Code** this requires the [Dev Container extension](https://containers.dev/supporting#dev-containers). +```shell +docker compose -f .devcontainer/compose.yaml up -d +docker compose -f .devcontainer/compose.yaml exec app bin/setup +docker compose -f .devcontainer/compose.yaml exec app bin/dev +``` + +### Dev Containers + +Within IDEs that support the [Development Containers] specification, start the +"Mastodon on local machine" container from the editor. The necessary `docker +compose` commands to build and setup the container should run automatically. For +**Visual Studio Code** this requires installing the [Dev Container extension]. ### GitHub Codespaces -To get you coding in just a few minutes, GitHub Codespaces provides a web-based version of Visual Studio Code and a cloud-hosted development environment fully configured with the software needed for this project.. +[GitHub Codespaces] provides a web-based version of VS Code and a cloud hosted +development environment configured with the software needed for this project. -- Click this button to create a new codespace:
- [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=52281283&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json) -- Wait for the environment to build. This will take a few minutes. -- When the editor is ready, run `bin/dev` in the terminal. -- After a few seconds, a popup will appear with a button labeled _Open in Browser_. This will open Mastodon. -- On the _Ports_ tab, right click on the “stream” row and select _Port visibility_ → _Public_. +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)][codespace] + +- Click the button to create a new codespace, and confirm the options +- Wait for the environment to build (takes a few minutes) +- When the editor is ready, run `bin/dev` in the terminal +- Wait for an _Open in Browser_ prompt. This will open Mastodon +- On the _Ports_ tab "stream" setting change _Port visibility_ → _Public_ ## Contributing @@ -140,3 +149,9 @@ This program is free software: you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + +[codespace]: https://codespaces.new/mastodon/mastodon?quickstart=1&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json +[Dev Container extension]: https://containers.dev/supporting#dev-containers +[Development Containers]: https://containers.dev/supporting +[Docker]: https://docs.docker.com +[GitHub Codespaces]: https://docs.github.com/en/codespaces From aab5b10c385168a6e47b985675f9e72ff020e8d1 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 8 Jun 2024 04:29:18 +0000 Subject: [PATCH 344/658] New Crowdin translations --- .../flavours/glitch/locales/fr-CA.json | 11 +++++++++++ app/javascript/flavours/glitch/locales/fr.json | 17 ++++++++++++++--- config/locales-glitch/fr.yml | 2 +- config/locales-glitch/no.yml | 2 +- config/locales-glitch/simple_form.fr.yml | 2 +- config/locales-glitch/simple_form.no.yml | 2 +- 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/javascript/flavours/glitch/locales/fr-CA.json b/app/javascript/flavours/glitch/locales/fr-CA.json index 30ca374d20..991d206a99 100644 --- a/app/javascript/flavours/glitch/locales/fr-CA.json +++ b/app/javascript/flavours/glitch/locales/fr-CA.json @@ -14,9 +14,15 @@ "column_subheading.lists": "Listes", "column_subheading.navigation": "Navigation", "community.column_settings.allow_local_only": "Afficher seulement les posts locaux", + "compose.attach.doodle": "Dessinez quelque chose", + "compose.change_federation": "Changer les paramètres de fédération", + "compose.content-type.change": "Changer les options de mise en forme avancée", "compose.content-type.html": "HTML", + "compose.content-type.html_meta": "Formatez vos messages en HTML", "compose.content-type.markdown": "Markdown", + "compose.content-type.markdown_meta": "Formatez vos messages en Markdown", "compose.content-type.plain": "Text brut", + "compose.content-type.plain_meta": "Écrire sans formatage avancé", "compose.disable_threaded_mode": "Désactiver le mode thread", "compose.enable_threaded_mode": "Activer le mode thread", "confirmation_modal.do_not_ask_again": "Ne plus demander confirmation", @@ -32,6 +38,10 @@ "direct.group_by_conversations": "Grouper par conversation", "endorsed_accounts_editor.endorsed_accounts": "Comptes mis en avant", "favourite_modal.combo": "Vous pouvez appuyer sur {combo} pour passer ceci la prochaine fois", + "federation.federated.long": "Permettre à ce post d’atteindre d'autres serveurs", + "federation.federated.short": "Fédéré", + "federation.local_only.long": "Empêcher ce post d’atteindre d'autres serveurs", + "federation.local_only.short": "Local uniquement", "firehose.column_settings.allow_local_only": "Afficher les messages locaux dans \"Tous\"", "home.column_settings.advanced": "Avancé", "home.column_settings.filter_regex": "Filtrer par expression régulière", @@ -114,6 +124,7 @@ "settings.shared_settings_link": "préférences de l'utilisateur", "settings.show_action_bar": "Afficher les boutons d'action dans les posts repliés", "settings.show_content_type_choice": "Afficher le choix du type de contenu lors de la création des posts", + "settings.show_published_toast": "Afficher une notification quand un post est envoyé/sauvegardé", "settings.show_reply_counter": "Afficher une estimation du nombre de réponses", "settings.side_arm": "Bouton secondaire de publication :", "settings.side_arm.none": "Aucun", diff --git a/app/javascript/flavours/glitch/locales/fr.json b/app/javascript/flavours/glitch/locales/fr.json index 30ca374d20..03baa0fb67 100644 --- a/app/javascript/flavours/glitch/locales/fr.json +++ b/app/javascript/flavours/glitch/locales/fr.json @@ -14,9 +14,15 @@ "column_subheading.lists": "Listes", "column_subheading.navigation": "Navigation", "community.column_settings.allow_local_only": "Afficher seulement les posts locaux", + "compose.attach.doodle": "Dessinez quelque chose", + "compose.change_federation": "Changer les paramètres de fédération", + "compose.content-type.change": "Changer les options de mise en forme avancée", "compose.content-type.html": "HTML", + "compose.content-type.html_meta": "Formatez vos messages en HTML", "compose.content-type.markdown": "Markdown", + "compose.content-type.markdown_meta": "Formatez vos messages en Markdown", "compose.content-type.plain": "Text brut", + "compose.content-type.plain_meta": "Écrire sans formatage avancé", "compose.disable_threaded_mode": "Désactiver le mode thread", "compose.enable_threaded_mode": "Activer le mode thread", "confirmation_modal.do_not_ask_again": "Ne plus demander confirmation", @@ -32,6 +38,10 @@ "direct.group_by_conversations": "Grouper par conversation", "endorsed_accounts_editor.endorsed_accounts": "Comptes mis en avant", "favourite_modal.combo": "Vous pouvez appuyer sur {combo} pour passer ceci la prochaine fois", + "federation.federated.long": "Permettre à ce post d’atteindre d'autres serveurs", + "federation.federated.short": "Fédéré", + "federation.local_only.long": "Empêcher ce post d’atteindre d'autres serveurs", + "federation.local_only.short": "Local uniquement", "firehose.column_settings.allow_local_only": "Afficher les messages locaux dans \"Tous\"", "home.column_settings.advanced": "Avancé", "home.column_settings.filter_regex": "Filtrer par expression régulière", @@ -65,9 +75,9 @@ "settings.close": "Fermer", "settings.collapsed_statuses": "Posts repliés", "settings.compose_box_opts": "Zone de rédaction", - "settings.confirm_before_clearing_draft": "Afficher une fenêtre de confirmation avant d'écraser le message en cours de rédaction", - "settings.confirm_boost_missing_media_description": "Afficher une fenêtre de confirmation avant de partager des posts manquant de description des médias", - "settings.confirm_missing_media_description": "Afficher une fenêtre de confirmation avant de publier des posts manquant de description de média", + "settings.confirm_before_clearing_draft": "Demander confirmation avant d’effacer le message en cours de rédaction", + "settings.confirm_boost_missing_media_description": "Demander confirmation avant de partager des posts sans description des médias", + "settings.confirm_missing_media_description": "Demander confirmation avant de publier des posts sans description des médias", "settings.content_warnings": "Content warnings", "settings.content_warnings.regexp": "Expression rationnelle", "settings.content_warnings_filter": "Avertissement de contenu à ne pas automatiquement déplier :", @@ -114,6 +124,7 @@ "settings.shared_settings_link": "préférences de l'utilisateur", "settings.show_action_bar": "Afficher les boutons d'action dans les posts repliés", "settings.show_content_type_choice": "Afficher le choix du type de contenu lors de la création des posts", + "settings.show_published_toast": "Afficher une notification quand un post est envoyé/sauvegardé", "settings.show_reply_counter": "Afficher une estimation du nombre de réponses", "settings.side_arm": "Bouton secondaire de publication :", "settings.side_arm.none": "Aucun", diff --git a/config/locales-glitch/fr.yml b/config/locales-glitch/fr.yml index 15c3f8ce52..7324c3db91 100644 --- a/config/locales-glitch/fr.yml +++ b/config/locales-glitch/fr.yml @@ -34,7 +34,7 @@ fr: glitch_guide_link_text: Et c'est pareil avec glitch-soc ! auth: captcha_confirmation: - hint_html: Plus qu'une étape ! Pour vérifier votre compte sur ce serveur, vous devez résoudre un CAPTCHA. Vous pouvez contacter l'administrateur·ice du serveur si vous avez des questions ou besoin d'assistance dans la vérification de votre compte. + hint_html: Plus qu'une étape ! Pour vérifier votre compte sur ce serveur, vous devez résoudre un CAPTCHA. Vous pouvez contacter l'administrateur·ice du serveur si vous avez des questions ou besoin d'assistance pour vérifier votre compte. title: Vérification de l'utilisateur generic: use_this: Utiliser ceci diff --git a/config/locales-glitch/no.yml b/config/locales-glitch/no.yml index d36c60a4ac..d2a4697e5d 100644 --- a/config/locales-glitch/no.yml +++ b/config/locales-glitch/no.yml @@ -1 +1 @@ -'no': +no: diff --git a/config/locales-glitch/simple_form.fr.yml b/config/locales-glitch/simple_form.fr.yml index a01d9a5f0f..f80b153723 100644 --- a/config/locales-glitch/simple_form.fr.yml +++ b/config/locales-glitch/simple_form.fr.yml @@ -16,7 +16,7 @@ fr: setting_default_content_type_html: HTML setting_default_content_type_markdown: Markdown setting_default_content_type_plain: Texte brut - setting_favourite_modal: Afficher une fenêtre de confirmation avant de mettre en favori un post (s'applique uniquement au mode Glitch) + setting_favourite_modal: Demander confirmation avant de mettre un post en favori (s'applique uniquement au mode Glitch) setting_show_followers_count: Cacher votre nombre d'abonné·e·s setting_skin: Thème setting_system_emoji_font: Utiliser la police par défaut du système pour les émojis (s'applique uniquement au mode Glitch) diff --git a/config/locales-glitch/simple_form.no.yml b/config/locales-glitch/simple_form.no.yml index d36c60a4ac..d2a4697e5d 100644 --- a/config/locales-glitch/simple_form.no.yml +++ b/config/locales-glitch/simple_form.no.yml @@ -1 +1 @@ -'no': +no: From c1a84f1b5b85e98c78847ddf03d1490300bcdc9d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Sat, 8 Jun 2024 06:32:39 -0400 Subject: [PATCH 345/658] Case correction `Github` -> `GitHub` (#30446) Co-authored-by: Igor --- .github/codecov.yml | 4 ++-- .github/renovate.json5 | 2 +- .github/workflows/build-container-image.yml | 2 +- .github/workflows/crowdin-download.yml | 4 ++-- SECURITY.md | 2 +- crowdin.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index 9d6413a106..701ba3af8f 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -3,9 +3,9 @@ coverage: status: project: default: - # Github status check is not blocking + # GitHub status check is not blocking informational: true patch: default: - # Github status check is not blocking + # GitHub status check is not blocking informational: true diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 378d4fc83c..52f7c63e5b 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -59,7 +59,7 @@ dependencyDashboardApproval: true, }, { - // Update Github Actions and Docker images weekly + // Update GitHub Actions and Docker images weekly matchManagers: ['github-actions', 'dockerfile', 'docker-compose'], extends: ['schedule:weekly'], }, diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml index e100e15821..dbb32af9bf 100644 --- a/.github/workflows/build-container-image.yml +++ b/.github/workflows/build-container-image.yml @@ -68,7 +68,7 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Log in to the Github Container registry + - name: Log in to the GitHub Container registry if: contains(inputs.push_to_images, 'ghcr.io') uses: docker/login-action@v3 with: diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml index 1df7672d6c..e9da7cb26f 100644 --- a/.github/workflows/crowdin-download.yml +++ b/.github/workflows/crowdin-download.yml @@ -58,13 +58,13 @@ jobs: title: 'New Crowdin Translations (automated)' author: 'GitHub Actions ' body: | - New Crowdin translations, automated with Github Actions + New Crowdin translations, automated with GitHub Actions See `.github/workflows/crowdin-download.yml` This PR will be updated every day with new translations. - Due to a limitation in Github Actions, checks are not running on this PR without manual action. + Due to a limitation in GitHub Actions, checks are not running on this PR without manual action. If you want to run the checks, then close and re-open it. branch: i18n/crowdin/translations base: main diff --git a/SECURITY.md b/SECURITY.md index 81472b01b4..156954ce02 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ If you believe you've identified a security vulnerability in Mastodon (a bug that allows something to happen that shouldn't be possible), you can either: -- open a [Github security issue on the Mastodon project](https://github.com/mastodon/mastodon/security/advisories/new) +- open a [GitHub security issue on the Mastodon project](https://github.com/mastodon/mastodon/security/advisories/new) - reach us at You should _not_ report such issues on public GitHub issues or in other public spaces to give us time to publish a fix for the issue without exposing Mastodon's users to increased risk. diff --git a/crowdin.yml b/crowdin.yml index d05b0e69f5..991c5b8252 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,4 +1,4 @@ -# This is needed for the Github Action +# This is needed for the GitHub Action project_id_env: CROWDIN_PROJECT_ID api_token_env: CROWDIN_PERSONAL_TOKEN From 6952af137d17f65e65963e4d9ba129060fad9d3d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Sat, 8 Jun 2024 06:33:28 -0400 Subject: [PATCH 346/658] Install from nvmrc during devcontainer Dockerfile build (#30603) --- .devcontainer/Dockerfile | 12 +++++------- .devcontainer/compose.yaml | 4 ++-- bin/setup | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 113dd71880..c6dcc4d46a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,17 +1,15 @@ # For details, see https://github.com/devcontainers/images/tree/main/src/ruby FROM mcr.microsoft.com/devcontainers/ruby:1-3.3-bookworm -# Update existing node version, keep in sync with .nvmrc -ARG NODE_VERSION="20" -RUN . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1 +# Install node version from .nvmrc +WORKDIR /app +COPY .nvmrc . +RUN /bin/bash --login -i -c "nvm install" # Install additional OS packages RUN apt-get update && \ export DEBIAN_FRONTEND=noninteractive && \ apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg imagemagick libvips42 libpam-dev -# Install global node packages -RUN . /usr/local/share/nvm/nvm.sh && corepack enable 2>&1 - # Move welcome message to where VS Code expects it -COPY welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt +COPY .devcontainer/welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt diff --git a/.devcontainer/compose.yaml b/.devcontainer/compose.yaml index 4d6eb3c487..1e2e1ba7de 100644 --- a/.devcontainer/compose.yaml +++ b/.devcontainer/compose.yaml @@ -2,8 +2,8 @@ services: app: working_dir: /workspaces/mastodon/ build: - context: . - dockerfile: Dockerfile + context: .. + dockerfile: .devcontainer/Dockerfile volumes: - ..:/workspaces/mastodon:cached environment: diff --git a/bin/setup b/bin/setup index 93c6981d0b..4ccf4594b4 100755 --- a/bin/setup +++ b/bin/setup @@ -18,7 +18,7 @@ FileUtils.chdir APP_ROOT do system('bundle check') || system!('bundle install') puts "\n== Installing JS dependencies ==" - system! 'corepack prepare' + system! 'corepack enable' system! 'bin/yarn install --immutable' puts "\n== Preparing database ==" From 01a9b37c209439b674fda283bc65d94466f20fb6 Mon Sep 17 00:00:00 2001 From: Claire Date: Sat, 8 Jun 2024 13:28:41 +0200 Subject: [PATCH 347/658] Fix bogus translations --- config/locales-glitch/no.yml | 2 +- config/locales-glitch/simple_form.no.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales-glitch/no.yml b/config/locales-glitch/no.yml index d2a4697e5d..d36c60a4ac 100644 --- a/config/locales-glitch/no.yml +++ b/config/locales-glitch/no.yml @@ -1 +1 @@ -no: +'no': diff --git a/config/locales-glitch/simple_form.no.yml b/config/locales-glitch/simple_form.no.yml index d2a4697e5d..d36c60a4ac 100644 --- a/config/locales-glitch/simple_form.no.yml +++ b/config/locales-glitch/simple_form.no.yml @@ -1 +1 @@ -no: +'no': From 82fcb55680a31797a8e9a4f8c51c97b4ba78dbe9 Mon Sep 17 00:00:00 2001 From: Claire Date: Sat, 8 Jun 2024 13:49:02 +0200 Subject: [PATCH 348/658] Fix crowdin upload workflow not triggering on glitch-soc source string changes --- .github/workflows/crowdin-upload.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/crowdin-upload.yml b/.github/workflows/crowdin-upload.yml index 75d66c2a6b..32c09802b4 100644 --- a/.github/workflows/crowdin-upload.yml +++ b/.github/workflows/crowdin-upload.yml @@ -5,13 +5,13 @@ on: branches: - main paths: - - crowdin.yml - - app/javascript/mastodon/locales/en.json - - config/locales/en.yml - - config/locales/simple_form.en.yml - - config/locales/activerecord.en.yml - - config/locales/devise.en.yml - - config/locales/doorkeeper.en.yml + - crowdin-glitch.yml + - app/javascript/flavours/glitch/locales/en.json + - config/locales-glitch/en.yml + - config/locales-glitch/simple_form.en.yml + - config/locales-glitch/activerecord.en.yml + - config/locales-glitch/devise.en.yml + - config/locales-glitch/doorkeeper.en.yml - .github/workflows/crowdin-upload.yml jobs: From 827e36ff9ee22ec58c64322c0a9d78eaa2dd4875 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Sat, 8 Jun 2024 13:10:06 -0400 Subject: [PATCH 349/658] Fix `Capybara/NegationMatcher` cop in spec/system (#30616) --- spec/system/filters_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/filters_spec.rb b/spec/system/filters_spec.rb index 9d18e90460..a0cb965a61 100644 --- a/spec/system/filters_spec.rb +++ b/spec/system/filters_spec.rb @@ -46,7 +46,7 @@ describe 'Filters' do click_on I18n.t('filters.index.delete') end.to change(CustomFilter, :count).by(-1) - expect(page).to_not have_content(filter_title) + expect(page).to have_no_content(filter_title) end end From 33b3330dc767f1765d777cb62a7d96830b3385c3 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 9 Jun 2024 04:29:04 +0000 Subject: [PATCH 350/658] New Crowdin translations --- .../flavours/glitch/locales/pt-PT.json | 28 ++++++++++++++++++- config/locales-glitch/no.yml | 2 +- config/locales-glitch/simple_form.no.yml | 2 +- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/javascript/flavours/glitch/locales/pt-PT.json b/app/javascript/flavours/glitch/locales/pt-PT.json index fd0b010159..634f3db12a 100644 --- a/app/javascript/flavours/glitch/locales/pt-PT.json +++ b/app/javascript/flavours/glitch/locales/pt-PT.json @@ -7,6 +7,32 @@ "boost_modal.missing_description": "Este post contém alguns media sem descrição", "column.favourited_by": "Adicionado aos favoritos de", "column.heading": "Diversos", + "moved_to_warning": "Esta conta mudou-se para {moved_to_link} e, portanto, pode não aceitar novos seguidores.", + "navigation_bar.featured_users": "Utilizadores em destaque", + "notification.markForDeletion": "Marcada para eliminação", + "notification_purge.btn_all": "Seleccionar tudo", + "notification_purge.btn_apply": "Limpar Selecionadas", + "notification_purge.btn_none": "Desselecionar tudo", + "notification_purge.start": "Entrar em modo de limpeza de notificações", + "notifications.column_settings.filter_bar.show_bar": "Mostrar barra de filtros", + "notifications.marked_clear": "Limpar as notificações selecionadas", + "notifications.marked_clear_confirmation": "Tem a certeza que deseja limpar todas as notificações selecionadas permanentemente?", + "settings.always_show_spoilers_field": "Mostrar sempre o campo Aviso de Conteúdo", + "settings.auto_collapse": "Colapso automático", + "settings.auto_collapse_height": "Altura (em pixels) a partir do qual um toot é considerado longo", + "settings.auto_collapse_media": "Toots com conteúdo multimédia", "settings.content_warnings": "Content warnings", - "settings.preferences": "Preferences" + "settings.layout_opts": "Disposição do conteúdo", + "settings.media": "Conteúdo multimédia", + "settings.media_fullwidth": "Pré-visualização a todo o comprimento", + "settings.media_reveal_behind_cw": "Mostrar sempre conteúdos com aviso", + "settings.notifications.favicon_badge": "Mostrar número de notificações no distintivo da página", + "settings.notifications.tab_badge": "Mostrar número de notificações não lidas", + "settings.notifications.tab_badge.hint": "Mostra um distintivo com o número de notificações não lidas quando a coluna de notificações não está aberta", + "settings.notifications_opts": "Opções de notificação", + "settings.pop_in_left": "Esquerda", + "settings.pop_in_right": "Direita", + "settings.preferences": "Preferences", + "settings.prepend_cw_re": "Iniciar respostas a toots com aviso de conteúdo com \"re:\"", + "settings.preselect_on_reply": "Pré-seleccionar nomes de utilizador nas respostas" } diff --git a/config/locales-glitch/no.yml b/config/locales-glitch/no.yml index d36c60a4ac..d2a4697e5d 100644 --- a/config/locales-glitch/no.yml +++ b/config/locales-glitch/no.yml @@ -1 +1 @@ -'no': +no: diff --git a/config/locales-glitch/simple_form.no.yml b/config/locales-glitch/simple_form.no.yml index d36c60a4ac..d2a4697e5d 100644 --- a/config/locales-glitch/simple_form.no.yml +++ b/config/locales-glitch/simple_form.no.yml @@ -1 +1 @@ -'no': +no: From 57959642e3fb278b55f8321156fb54e8bdba6a29 Mon Sep 17 00:00:00 2001 From: Claire Date: Sun, 9 Jun 2024 18:33:41 +0200 Subject: [PATCH 351/658] Fix bogus translations --- config/locales-glitch/no.yml | 2 +- config/locales-glitch/simple_form.no.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales-glitch/no.yml b/config/locales-glitch/no.yml index d2a4697e5d..d36c60a4ac 100644 --- a/config/locales-glitch/no.yml +++ b/config/locales-glitch/no.yml @@ -1 +1 @@ -no: +'no': diff --git a/config/locales-glitch/simple_form.no.yml b/config/locales-glitch/simple_form.no.yml index d2a4697e5d..d36c60a4ac 100644 --- a/config/locales-glitch/simple_form.no.yml +++ b/config/locales-glitch/simple_form.no.yml @@ -1 +1 @@ -no: +'no': From 0cf91213c93e87ce775453ae20a3d9a7f9b4e8d0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 10 Jun 2024 02:32:20 -0400 Subject: [PATCH 352/658] Opt in to remaining Rails 7.1 defaults (#30332) Co-authored-by: Claire --- config/application.rb | 5 +- .../initializers/active_record_encryption.rb | 5 + .../new_framework_defaults_7_1.rb | 214 ------------------ 3 files changed, 8 insertions(+), 216 deletions(-) delete mode 100644 config/initializers/new_framework_defaults_7_1.rb diff --git a/config/application.rb b/config/application.rb index 069eb37740..b3a9b99ff5 100644 --- a/config/application.rb +++ b/config/application.rb @@ -60,9 +60,10 @@ Bundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true' module Mastodon class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 7.0 + config.load_defaults 7.1 - config.active_record.marshalling_format_version = 7.1 + # Explicitly set the cache format version to align with Rails version + config.active_support.cache_format_version = 7.1 # Please, add to the `ignore` list any other `lib` subdirectories that do # not contain `.rb` files, or that should not be reloaded or eager loaded. diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb index 777bafc273..900f3c68f0 100644 --- a/config/initializers/active_record_encryption.rb +++ b/config/initializers/active_record_encryption.rb @@ -32,4 +32,9 @@ Rails.application.configure do config.active_record.encryption.deterministic_key = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY') config.active_record.encryption.key_derivation_salt = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT') config.active_record.encryption.primary_key = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY') + config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true + + # TODO: https://github.com/rails/rails/issues/50604#issuecomment-1880990392 + # Remove after updating to Rails 7.1.4 + ActiveRecord::Encryption.configure(**config.active_record.encryption) end diff --git a/config/initializers/new_framework_defaults_7_1.rb b/config/initializers/new_framework_defaults_7_1.rb deleted file mode 100644 index bcc300c89f..0000000000 --- a/config/initializers/new_framework_defaults_7_1.rb +++ /dev/null @@ -1,214 +0,0 @@ -# frozen_string_literal: true - -# Be sure to restart your server when you modify this file. -# -# This file eases your Rails 7.1 framework defaults upgrade. -# -# Uncomment each configuration one by one to switch to the new default. -# Once your application is ready to run with all new defaults, you can remove -# this file and set the `config.load_defaults` to `7.1`. -# -# Read the Guide for Upgrading Ruby on Rails for more info on each option. -# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html - -# No longer add autoloaded paths into `$LOAD_PATH`. This means that you won't be able -# to manually require files that are managed by the autoloader, which you shouldn't do anyway. -# This will reduce the size of the load path, making `require` faster if you don't use bootsnap, or reduce the size -# of the bootsnap cache if you use it. -Rails.application.config.add_autoload_paths_to_load_path = false - -# Remove the default X-Download-Options headers since it is used only by Internet Explorer. -# If you need to support Internet Explorer, add back `"X-Download-Options" => "noopen"`. -# Rails.application.config.action_dispatch.default_headers = { -# "X-Frame-Options" => "SAMEORIGIN", -# "X-XSS-Protection" => "0", -# "X-Content-Type-Options" => "nosniff", -# "X-Permitted-Cross-Domain-Policies" => "none", -# "Referrer-Policy" => "strict-origin-when-cross-origin" -# } - -# Do not treat an `ActionController::Parameters` instance -# as equal to an equivalent `Hash` by default. -Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false - -# Active Record Encryption now uses SHA-256 as its hash digest algorithm. Important: If you have -# data encrypted with previous Rails versions, there are two scenarios to consider: -# -# 1. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA1 (the default -# before Rails 7.0), you need to configure SHA-1 for Active Record Encryption too: -# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1 -# 2. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA256 (the new default -# in 7.0), then you need to configure SHA-256 for Active Record Encryption: -# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA256 -# -# If you don't currently have data encrypted with Active Record encryption, you can disable this setting to -# configure the default behavior starting 7.1+: -# Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = false - -# No longer run after_commit callbacks on the first of multiple Active Record -# instances to save changes to the same database row within a transaction. -# Instead, run these callbacks on the instance most likely to have internal -# state which matches what was committed to the database, typically the last -# instance to save. -Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false - -# Configures SQLite with a strict strings mode, which disables double-quoted string literals. -# -# SQLite has some quirks around double-quoted string literals. -# It first tries to consider double-quoted strings as identifier names, but if they don't exist -# it then considers them as string literals. Because of this, typos can silently go unnoticed. -# For example, it is possible to create an index for a non existing column. -# See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted for more details. -Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true - -# Disable deprecated singular associations names -Rails.application.config.active_record.allow_deprecated_singular_associations_name = false - -# Enable the Active Job `BigDecimal` argument serializer, which guarantees -# roundtripping. Without this serializer, some queue adapters may serialize -# `BigDecimal` arguments as simple (non-roundtrippable) strings. -# -# When deploying an application with multiple replicas, old (pre-Rails 7.1) -# replicas will not be able to deserialize `BigDecimal` arguments from this -# serializer. Therefore, this setting should only be enabled after all replicas -# have been successfully upgraded to Rails 7.1. -# Rails.application.config.active_job.use_big_decimal_serializer = true - -# Specify if an `ArgumentError` should be raised if `Rails.cache` `fetch` or -# `write` are given an invalid `expires_at` or `expires_in` time. -# Options are `true`, and `false`. If `false`, the exception will be reported -# as `handled` and logged instead. -Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true - -# Specify whether Query Logs will format tags using the SQLCommenter format -# (https://open-telemetry.github.io/opentelemetry-sqlcommenter/), or using the legacy format. -# Options are `:legacy` and `:sqlcommenter`. -Rails.application.config.active_record.query_log_tags_format = :sqlcommenter - -# Specify the default serializer used by `MessageEncryptor` and `MessageVerifier` -# instances. -# -# The legacy default is `:marshal`, which is a potential vector for -# deserialization attacks in cases where a message signing secret has been -# leaked. -# -# In Rails 7.1, the new default is `:json_allow_marshal` which serializes and -# deserializes with `ActiveSupport::JSON`, but can fall back to deserializing -# with `Marshal` so that legacy messages can still be read. -# -# In Rails 7.2, the default will become `:json` which serializes and -# deserializes with `ActiveSupport::JSON` only. -# -# Alternatively, you can choose `:message_pack` or `:message_pack_allow_marshal`, -# which serialize with `ActiveSupport::MessagePack`. `ActiveSupport::MessagePack` -# can roundtrip some Ruby types that are not supported by JSON, and may provide -# improved performance, but it requires the `msgpack` gem. -# -# For more information, see -# https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer -# -# If you are performing a rolling deploy of a Rails 7.1 upgrade, wherein servers -# that have not yet been upgraded must be able to read messages from upgraded -# servers, first deploy without changing the serializer, then set the serializer -# in a subsequent deploy. -# Rails.application.config.active_support.message_serializer = :json_allow_marshal - -# Enable a performance optimization that serializes message data and metadata -# together. This changes the message format, so messages serialized this way -# cannot be read by older versions of Rails. However, messages that use the old -# format can still be read, regardless of whether this optimization is enabled. -# -# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have -# not yet been upgraded must be able to read messages from upgraded servers, -# leave this optimization off on the first deploy, then enable it on a -# subsequent deploy. -# Rails.application.config.active_support.use_message_serializer_for_metadata = true - -# Set the maximum size for Rails log files. -# -# `config.load_defaults 7.1` does not set this value for environments other than -# development and test. -# -Rails.application.config.log_file_size = 100 * 1024 * 1024 if Rails.env.local? - -# Enable raising on assignment to attr_readonly attributes. The previous -# behavior would allow assignment but silently not persist changes to the -# database. -Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true - -# Enable validating only parent-related columns for presence when the parent is mandatory. -# The previous behavior was to validate the presence of the parent record, which performed an extra query -# to get the parent every time the child record was updated, even when parent has not changed. -Rails.application.config.active_record.belongs_to_required_validates_foreign_key = false - -# Enable precompilation of `config.filter_parameters`. Precompilation can -# improve filtering performance, depending on the quantity and types of filters. -Rails.application.config.precompile_filter_parameters = true - -# Enable before_committed! callbacks on all enrolled records in a transaction. -# The previous behavior was to only run the callbacks on the first copy of a record -# if there were multiple copies of the same record enrolled in the transaction. -Rails.application.config.active_record.before_committed_on_all_records = true - -# Disable automatic column serialization into YAML. -# To keep the historic behavior, you can set it to `YAML`, however it is -# recommended to explicitly define the serialization method for each column -# rather than to rely on a global default. -Rails.application.config.active_record.default_column_serializer = nil - -# Run `after_commit` and `after_*_commit` callbacks in the order they are defined in a model. -# This matches the behaviour of all other callbacks. -# In previous versions of Rails, they ran in the inverse order. -Rails.application.config.active_record.run_after_transaction_callbacks_in_order_defined = true - -# Whether a `transaction` block is committed or rolled back when exited via `return`, `break` or `throw`. -# -# Rails.application.config.active_record.commit_transaction_on_non_local_return = true - -# Controls when to generate a value for has_secure_token declarations. -# -Rails.application.config.active_record.generate_secure_token_on = :initialize - -# ** Please read carefully, this must be configured in config/application.rb ** -# Change the format of the cache entry. -# Changing this default means that all new cache entries added to the cache -# will have a different format that is not supported by Rails 7.0 -# applications. -# Only change this value after your application is fully deployed to Rails 7.1 -# and you have no plans to rollback. -# When you're ready to change format, add this to `config/application.rb` (NOT -# this file): -# config.active_support.cache_format_version = 7.1 - -# Configure Action View to use HTML5 standards-compliant sanitizers when they are supported on your -# platform. -# -# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action View to use HTML5-compliant -# sanitizers if they are supported, else fall back to HTML4 sanitizers. -# -# In previous versions of Rails, Action View always used `Rails::HTML4::Sanitizer` as its vendor. -# -Rails.application.config.action_view.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor - -# Configure Action Text to use an HTML5 standards-compliant sanitizer when it is supported on your -# platform. -# -# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action Text to use HTML5-compliant -# sanitizers if they are supported, else fall back to HTML4 sanitizers. -# -# In previous versions of Rails, Action Text always used `Rails::HTML4::Sanitizer` as its vendor. -# -# Rails.application.config.action_text.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor - -# Configure the log level used by the DebugExceptions middleware when logging -# uncaught exceptions during requests -# Rails.application.config.action_dispatch.debug_exception_log_level = :error - -# Configure the test helpers in Action View, Action Dispatch, and rails-dom-testing to use HTML5 -# parsers. -# -# Nokogiri::HTML5 isn't supported on JRuby, so JRuby applications must set this to :html4. -# -# In previous versions of Rails, these test helpers always used an HTML4 parser. -# -Rails.application.config.dom_testing_default_html_version = :html5 From 77c2216e47c8ffba4dde91c1a300cf924a8e5c05 Mon Sep 17 00:00:00 2001 From: Daniel M Brasil Date: Mon, 10 Jun 2024 10:33:48 -0300 Subject: [PATCH 353/658] fix: Return HTTP 422 when scheduled status time is less than 5 minutes (#30584) --- app/services/post_status_service.rb | 2 +- spec/requests/api/v1/statuses_spec.rb | 26 +++++++++++++++++++++++ spec/services/post_status_service_spec.rb | 10 +++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 83a9318170..8b18ce038d 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -171,7 +171,7 @@ class PostStatusService < BaseService end def scheduled_in_the_past? - @scheduled_at.present? && @scheduled_at <= Time.now.utc + MIN_SCHEDULE_OFFSET + @scheduled_at.present? && @scheduled_at <= Time.now.utc end def bump_potential_friendship! diff --git a/spec/requests/api/v1/statuses_spec.rb b/spec/requests/api/v1/statuses_spec.rb index 694861fb1c..2f99b35e74 100644 --- a/spec/requests/api/v1/statuses_spec.rb +++ b/spec/requests/api/v1/statuses_spec.rb @@ -193,6 +193,32 @@ describe '/api/v1/statuses' do expect(response).to have_http_status(404) end end + + context 'when scheduling a status' do + let(:params) { { status: 'Hello world', scheduled_at: 10.minutes.from_now } } + let(:account) { user.account } + + it 'returns HTTP 200' do + subject + + expect(response).to have_http_status(200) + end + + it 'creates a scheduled status' do + expect { subject }.to change { account.scheduled_statuses.count }.from(0).to(1) + end + + context 'when the scheduling time is less than 5 minutes' do + let(:params) { { status: 'Hello world', scheduled_at: 4.minutes.from_now } } + + it 'does not create a scheduled status', :aggregate_failures do + subject + + expect(response).to have_http_status(422) + expect(account.scheduled_statuses).to be_empty + end + end + end end describe 'DELETE /api/v1/statuses/:id' do diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index 11bf4c30ea..f21548b5f2 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -61,6 +61,16 @@ RSpec.describe PostStatusService do status2 = subject.call(account, text: 'test', idempotency: 'meepmeep', scheduled_at: future) expect(status2.id).to eq status1.id end + + context 'when scheduled_at is less than min offset' do + let(:invalid_scheduled_time) { 4.minutes.from_now } + + it 'raises invalid record error' do + expect do + subject.call(account, text: 'Hi future!', scheduled_at: invalid_scheduled_time) + end.to raise_error(ActiveRecord::RecordInvalid) + end + end end it 'creates response to the original status of boost' do From 801f9feec3d23be013751a3c468356a1c3c6ddf7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 15:52:57 +0200 Subject: [PATCH 354/658] chore(deps): update dependency concurrent-ruby to v1.3.3 (#30605) 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 8ff990260b..93877e15d8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -168,7 +168,7 @@ GEM climate_control (1.2.0) cocoon (1.2.15) color_diff (0.1) - concurrent-ruby (1.3.1) + concurrent-ruby (1.3.3) connection_pool (2.4.1) cose (1.3.0) cbor (~> 0.5.9) From bfd674d819327b4af3053ec35aea96f0c9e36428 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:04:44 +0200 Subject: [PATCH 355/658] chore(deps): update dependency httplog to '~> 1.7.0' (#30613) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 136d074d33..be02a65626 100644 --- a/Gemfile +++ b/Gemfile @@ -57,7 +57,7 @@ gem 'hiredis', '~> 0.6' gem 'htmlentities', '~> 4.3' gem 'http', '~> 5.2.0' gem 'http_accept_language', '~> 2.1' -gem 'httplog', '~> 1.6.2' +gem 'httplog', '~> 1.7.0' gem 'i18n' gem 'idn-ruby', require: 'idn' gem 'inline_svg' diff --git a/Gemfile.lock b/Gemfile.lock index 93877e15d8..812e23a852 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -321,7 +321,7 @@ GEM http-form_data (2.3.0) http_accept_language (2.1.1) httpclient (2.8.3) - httplog (1.6.3) + httplog (1.7.0) rack (>= 2.0) rainbow (>= 2.0.0) i18n (1.14.5) @@ -947,7 +947,7 @@ DEPENDENCIES htmlentities (~> 4.3) http (~> 5.2.0) http_accept_language (~> 2.1) - httplog (~> 1.6.2) + httplog (~> 1.7.0) i18n i18n-tasks (~> 1.0) idn-ruby From 2dca6ec77ad8be8674cde103578c416095a3522b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:05:57 +0200 Subject: [PATCH 356/658] chore(deps): update dependency oj to v3.16.4 (#30620) 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 812e23a852..095433981a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -453,7 +453,7 @@ GEM concurrent-ruby (~> 1.0, >= 1.0.2) sidekiq (>= 3.5) statsd-ruby (~> 1.4, >= 1.4.0) - oj (3.16.3) + oj (3.16.4) bigdecimal (>= 3.0) omniauth (2.1.2) hashie (>= 3.4.6) From 452872412dd5a3af0ca9186726bf5a5fb8038856 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:07:35 +0200 Subject: [PATCH 357/658] chore(deps): update dependency @types/lodash to v4.17.5 (#30627) 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 dcc17d6599..e3d3bebeb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3712,9 +3712,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.195": - version: 4.17.4 - resolution: "@types/lodash@npm:4.17.4" - checksum: 10c0/0124c64cb9fe7a0f78b6777955abd05ef0d97844d49118652eae45f8fa57bfb7f5a7a9bccc0b5a84c0a6dc09631042e4590cb665acb9d58dfd5e6543c75341ec + version: 4.17.5 + resolution: "@types/lodash@npm:4.17.5" + checksum: 10c0/55924803ed853e72261512bd3eaf2c5b16558c3817feb0a3125ef757afe46e54b86f33d1960e40b7606c0ddab91a96f47966bf5e6006b7abfd8994c13b04b19b languageName: node linkType: hard From dd4a976122ac1da57ac011f84d71e168ad911cfe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:08:02 +0200 Subject: [PATCH 358/658] chore(deps): update devdependencies (non-major) (#30628) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index e3d3bebeb1..8a1f96b69a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13062,8 +13062,8 @@ __metadata: linkType: hard "pino-pretty@npm:^11.0.0": - version: 11.1.0 - resolution: "pino-pretty@npm:11.1.0" + version: 11.2.0 + resolution: "pino-pretty@npm:11.2.0" dependencies: colorette: "npm:^2.0.7" dateformat: "npm:^4.6.3" @@ -13081,7 +13081,7 @@ __metadata: strip-json-comments: "npm:^3.1.1" bin: pino-pretty: bin.js - checksum: 10c0/418be6f854b0d62c83c65e75b0969d5311792bfadeefbfe77d8a7f8c5ba26b8bea40f549222b5f500439f440eb4d6c2fa99d712bdd02881ebae7be3a0193b581 + checksum: 10c0/59421522c0e07877614ed8b51eb45fe79aad9865244b95dfaf5e28c83f9e95631941b5b9e37a277d1751ed90903d7593915e8a8857cc856b4af7e6bf20a5f97d languageName: node linkType: hard @@ -14022,11 +14022,11 @@ __metadata: linkType: hard "prettier@npm:^3.0.0": - version: 3.3.0 - resolution: "prettier@npm:3.3.0" + version: 3.3.1 + resolution: "prettier@npm:3.3.1" bin: prettier: bin/prettier.cjs - checksum: 10c0/d033c356320aa2e468bf29c931b094ac730d2f4defd5eb2989d8589313dec901d2fc866e3788f3d161e420b142ea4ec3dda535dbe0169ef4d0026397a68ba9cf + checksum: 10c0/c25a709c9f0be670dc6bcb190b622347e1dbeb6c3e7df8b0711724cb64d8647c60b839937a4df4df18e9cfb556c2b08ca9d24d9645eb5488a7fc032a2c4d5cb3 languageName: node linkType: hard From a6e0e167a71025b27719666906cfb5511734134e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:29:11 +0200 Subject: [PATCH 359/658] fix(deps): update dependency uuid to v10 (#30624) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- streaming/package.json | 2 +- yarn.lock | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/streaming/package.json b/streaming/package.json index cf1fe4ba69..2e515167c7 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -27,7 +27,7 @@ "pino": "^9.0.0", "pino-http": "^10.0.0", "prom-client": "^15.0.0", - "uuid": "^9.0.0", + "uuid": "^10.0.0", "ws": "^8.12.1" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 8a1f96b69a..33cd7b481d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2942,7 +2942,7 @@ __metadata: prom-client: "npm:^15.0.0" typescript: "npm:^5.0.4" utf-8-validate: "npm:^6.0.3" - uuid: "npm:^9.0.0" + uuid: "npm:^10.0.0" ws: "npm:^8.12.1" dependenciesMeta: bufferutil: @@ -17489,6 +17489,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^10.0.0": + version: 10.0.0 + resolution: "uuid@npm:10.0.0" + bin: + uuid: dist/bin/uuid + checksum: 10c0/eab18c27fe4ab9fb9709a5d5f40119b45f2ec8314f8d4cf12ce27e4c6f4ffa4a6321dc7db6c515068fa373c075b49691ba969f0010bf37f44c37ca40cd6bf7fe + languageName: node + linkType: hard + "uuid@npm:^3.3.2": version: 3.4.0 resolution: "uuid@npm:3.4.0" @@ -17507,15 +17516,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^9.0.0": - version: 9.0.1 - resolution: "uuid@npm:9.0.1" - bin: - uuid: dist/bin/uuid - checksum: 10c0/1607dd32ac7fc22f2d8f77051e6a64845c9bce5cd3dd8aa0070c074ec73e666a1f63c7b4e0f4bf2bc8b9d59dc85a15e17807446d9d2b17c8485fbc2147b27f9b - languageName: node - linkType: hard - "v8-compile-cache@npm:^2.1.1": version: 2.3.0 resolution: "v8-compile-cache@npm:2.3.0" From 589365ba52b5e982f31c7acbb0a264bc378e061b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:29:26 +0200 Subject: [PATCH 360/658] chore(deps): update dependency rubocop-capybara to v2.21.0 (#30611) 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 095433981a..4d16fea47c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -578,7 +578,7 @@ GEM opentelemetry-api (~> 1.0) orm_adapter (0.5.0) ox (2.14.18) - parallel (1.24.0) + parallel (1.25.1) parser (3.3.2.0) ast (~> 2.4.1) racc @@ -739,7 +739,7 @@ GEM unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.31.3) parser (>= 3.3.1.0) - rubocop-capybara (2.20.0) + rubocop-capybara (2.21.0) rubocop (~> 1.41) rubocop-factory_bot (2.25.1) rubocop (~> 1.41) From bb27321781778d4d849dd0a4c2f16747f85f1a3d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 16:29:30 +0200 Subject: [PATCH 361/658] New Crowdin Translations (automated) (#30608) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/eo.json | 7 ++ app/javascript/mastodon/locales/fr-CA.json | 6 +- app/javascript/mastodon/locales/fr.json | 6 +- app/javascript/mastodon/locales/ia.json | 4 +- app/javascript/mastodon/locales/id.json | 10 ++ app/javascript/mastodon/locales/la.json | 125 +++++++++++++++++++-- config/locales/devise.la.yml | 7 ++ config/locales/doorkeeper.ja.yml | 2 + config/locales/doorkeeper.lad.yml | 2 + config/locales/doorkeeper.lt.yml | 2 + config/locales/doorkeeper.sv.yml | 1 + config/locales/doorkeeper.th.yml | 2 + config/locales/doorkeeper.vi.yml | 2 + config/locales/id.yml | 6 + config/locales/la.yml | 33 ++++++ config/locales/nl.yml | 4 +- config/locales/simple_form.id.yml | 3 + config/locales/th.yml | 4 +- 18 files changed, 204 insertions(+), 22 deletions(-) diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 6e7885f485..2dbbf78773 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -498,7 +498,14 @@ "poll_button.add_poll": "Aldoni balotenketon", "poll_button.remove_poll": "Forigi balotenketon", "privacy.change": "Agordi mesaĝan privatecon", + "privacy.direct.long": "Ĉiuj menciitaj en la afiŝo", + "privacy.direct.short": "Specifaj homoj", + "privacy.private.long": "Nur viaj sekvantoj", + "privacy.private.short": "Sekvantoj", + "privacy.public.long": "Ĉiujn ajn ĉe kaj ekster Mastodon", "privacy.public.short": "Publika", + "privacy.unlisted.long": "Malpli algoritmaj fanfaroj", + "privacy.unlisted.short": "Diskrete publika", "privacy_policy.last_updated": "Laste ĝisdatigita en {date}", "privacy_policy.title": "Politiko de privateco", "recommended": "Rekomendita", diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json index 9e29852904..9c14d05d5c 100644 --- a/app/javascript/mastodon/locales/fr-CA.json +++ b/app/javascript/mastodon/locales/fr-CA.json @@ -156,7 +156,7 @@ "compose_form.poll.duration": "Durée du sondage", "compose_form.poll.multiple": "Choix multiple", "compose_form.poll.option_placeholder": "Option {number}", - "compose_form.poll.single": "Choisissez-en un", + "compose_form.poll.single": "Choix unique", "compose_form.poll.switch_to_multiple": "Changer le sondage pour autoriser plusieurs choix", "compose_form.poll.switch_to_single": "Changer le sondage pour n'autoriser qu'un seul choix", "compose_form.poll.type": "Style", @@ -585,9 +585,9 @@ "privacy.private.short": "Abonnés", "privacy.public.long": "Tout le monde sur et en dehors de Mastodon", "privacy.public.short": "Public", - "privacy.unlisted.additional": "Cette option se comporte exactement comme l'option publique, sauf que le message n'apparaîtra pas dans les flux en direct, les hashtags, l'exploration ou la recherche Mastodon, même si vous avez opté pour l'option publique pour l'ensemble de votre compte.", + "privacy.unlisted.additional": "Se comporte exactement comme « public », sauf que le message n'apparaîtra pas dans les flux en direct, les hashtags, explorer ou la recherche Mastodon, même si vous les avez activé au niveau de votre compte.", "privacy.unlisted.long": "Moins de fanfares algorithmiques", - "privacy.unlisted.short": "Public calme", + "privacy.unlisted.short": "Public discret", "privacy_policy.last_updated": "Dernière mise à jour {date}", "privacy_policy.title": "Politique de confidentialité", "recommended": "Recommandé", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 1a5803623f..36ec673a47 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -156,7 +156,7 @@ "compose_form.poll.duration": "Durée du sondage", "compose_form.poll.multiple": "Choix multiple", "compose_form.poll.option_placeholder": "Option {number}", - "compose_form.poll.single": "Choisissez-en un", + "compose_form.poll.single": "Choix unique", "compose_form.poll.switch_to_multiple": "Changer le sondage pour autoriser plusieurs choix", "compose_form.poll.switch_to_single": "Modifier le sondage pour autoriser qu'un seul choix", "compose_form.poll.type": "Style", @@ -585,9 +585,9 @@ "privacy.private.short": "Abonnés", "privacy.public.long": "Tout le monde sur et en dehors de Mastodon", "privacy.public.short": "Public", - "privacy.unlisted.additional": "Cette option se comporte exactement comme l'option publique, sauf que le message n'apparaîtra pas dans les flux en direct, les hashtags, l'exploration ou la recherche Mastodon, même si vous avez opté pour l'option publique pour l'ensemble de votre compte.", + "privacy.unlisted.additional": "Se comporte exactement comme « public », sauf que le message n'apparaîtra pas dans les flux en direct, les hashtags, explorer ou la recherche Mastodon, même si vous les avez activé au niveau de votre compte.", "privacy.unlisted.long": "Moins de fanfares algorithmiques", - "privacy.unlisted.short": "Public calme", + "privacy.unlisted.short": "Public discret", "privacy_policy.last_updated": "Dernière mise à jour {date}", "privacy_policy.title": "Politique de confidentialité", "recommended": "Recommandé", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index ce4e89e99a..ed33a45d45 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -19,7 +19,7 @@ "account.block_domain": "Blocar dominio {domain}", "account.block_short": "Blocar", "account.blocked": "Blocate", - "account.browse_more_on_origin_server": "Percurrer plus sur le profilo original", + "account.browse_more_on_origin_server": "Explorar plus sur le profilo original", "account.cancel_follow_request": "Cancellar sequimento", "account.copy": "Copiar ligamine a profilo", "account.direct": "Mentionar privatemente @{name}", @@ -111,7 +111,7 @@ "bundle_modal_error.message": "Un error ha occurrite durante le cargamento de iste componente.", "bundle_modal_error.retry": "Tentar novemente", "closed_registrations.other_server_instructions": "Perque Mastodon es decentralisate, tu pote crear un conto sur un altere servitor e totevia interager con iste servitor.", - "closed_registrations_modal.description": "Crear un conto in {domain} actualmente non es possibile, ma considera que non es necessari haber un conto specificamente sur {domain} pro usar Mastodon.", + "closed_registrations_modal.description": "Crear un conto sur {domain} non es actualmente possibile, ma considera que non es necessari haber un conto specificamente sur {domain} pro usar Mastodon.", "closed_registrations_modal.find_another_server": "Cercar un altere servitor", "closed_registrations_modal.preamble": "Mastodon es decentralisate, dunque, non importa ubi tu crea tu conto, tu pote sequer e communicar con omne persona sur iste servitor. Tu pote mesmo hospitar tu proprie servitor!", "closed_registrations_modal.title": "Crear un conto sur Mastodon", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index 33161f8882..79224c57df 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -299,6 +299,11 @@ "follow_suggestions.dismiss": "Jangan tampilkan lagi", "follow_suggestions.hints.featured": "Profil ini telah dipilih sendiri oleh tim {domain}.", "follow_suggestions.hints.friends_of_friends": "Profil ini populer di kalangan orang yang anda ikuti.", + "follow_suggestions.personalized_suggestion": "Saran yang dipersonalisasi", + "follow_suggestions.popular_suggestion": "Saran populer", + "follow_suggestions.popular_suggestion_longer": "Populer di {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Serupa dengan profil yang baru Anda ikuti", + "follow_suggestions.view_all": "Lihat semua", "followed_tags": "Tagar yang diikuti", "footer.about": "Tentang", "footer.directory": "Direktori profil", @@ -324,6 +329,7 @@ "home.column_settings.show_reblogs": "Tampilkan boost", "home.column_settings.show_replies": "Tampilkan balasan", "home.hide_announcements": "Sembunyikan pengumuman", + "home.pending_critical_update.link": "Lihat pembaruan", "home.show_announcements": "Tampilkan pengumuman", "interaction_modal.description.follow": "Dengan sebuah akun di Mastodon, Anda bisa mengikuti {name} untuk menerima kirimannya di beranda Anda.", "interaction_modal.description.reblog": "Dengan sebuah akun di Mastodon, Anda bisa mem-boost kiriman ini untuk membagikannya ke pengikut Anda sendiri.", @@ -375,6 +381,7 @@ "lightbox.previous": "Sebelumnya", "limited_account_hint.action": "Tetap tampilkan profil", "limited_account_hint.title": "Profil ini telah disembunyikan oleh moderator {domain}.", + "link_preview.author": "Oleh {name}", "lists.account.add": "Tambah ke daftar", "lists.account.remove": "Hapus dari daftar", "lists.delete": "Hapus daftar", @@ -389,8 +396,11 @@ "lists.search": "Cari di antara orang yang Anda ikuti", "lists.subheading": "Daftar Anda", "load_pending": "{count, plural, other {# item baru}}", + "loading_indicator.label": "Memuat…", "media_gallery.toggle_visible": "Tampil/Sembunyikan", "moved_to_account_banner.text": "Akun {disabledAccount} Anda kini dinonaktifkan karena Anda pindah ke {movedToAccount}.", + "mute_modal.hide_options": "Sembunyikan opsi", + "mute_modal.title": "Bisukan pengguna?", "navigation_bar.about": "Tentang", "navigation_bar.blocks": "Pengguna diblokir", "navigation_bar.bookmarks": "Markah", diff --git a/app/javascript/mastodon/locales/la.json b/app/javascript/mastodon/locales/la.json index a49ec94d72..4bee0efed4 100644 --- a/app/javascript/mastodon/locales/la.json +++ b/app/javascript/mastodon/locales/la.json @@ -1,7 +1,9 @@ { "about.contact": "Ratio:", "about.domain_blocks.no_reason_available": "Ratio abdere est", + "about.domain_blocks.silenced.explanation": "Tua profilia atque tuum contentum ab hac serve praecipue non videbis, nisi explōrēs expresse aut subsequeris et optēs.", "account.account_note_header": "Annotatio", + "account.add_or_remove_from_list": "Adde aut ēripe ex tabellīs", "account.badges.bot": "Robotum", "account.badges.group": "Congregatio", "account.block": "Impedire @{name}", @@ -11,11 +13,21 @@ "account.domain_blocked": "Dominium impeditum", "account.edit_profile": "Recolere notionem", "account.featured_tags.last_status_never": "Nulla contributa", + "account.featured_tags.title": "Hashtag notātī {name}", + "account.followers_counter": "{count, plural, one {{counter} Sectator} other {{counter} Sectatores}}", + "account.following_counter": "{count, plural, one {{counter} Sequens} other {{counter} Sequentes}}", + "account.moved_to": "{name} significavit eum suam rationem novam nunc esse:", "account.muted": "Confutatus", + "account.requested_follow": "{name} postulavit ut te sequeretur", + "account.statuses_counter": "{count, plural, one {{counter} Nuntius} other {{counter} Nuntii}}", "account.unblock_short": "Solvere impedimentum", "account_note.placeholder": "Click to add a note", "admin.dashboard.retention.average": "Mediocritas", + "admin.impact_report.instance_accounts": "Rationes perfiles hoc deleret", + "alert.unexpected.message": "Error inopinatus occurrit.", "announcement.announcement": "Proclamatio", + "attachments_list.unprocessed": "(immūtātus)", + "block_modal.you_wont_see_mentions": "Nuntios quibus eos commemorant non videbis.", "bundle_column_error.error.title": "Eheu!", "bundle_column_error.retry": "Retemptare", "bundle_column_error.routing.title": "CCCCIIII", @@ -37,26 +49,55 @@ "compose_form.placeholder": "What is on your mind?", "compose_form.publish_form": "Barrire", "compose_form.spoiler.marked": "Text is hidden behind warning", - "compose_form.spoiler.unmarked": "Text is not hidden", + "compose_form.spoiler.unmarked": "Adde praeconium contentūs", "confirmations.block.confirm": "Impedire", "confirmations.delete.confirm": "Oblitterare", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Oblitterare", + "confirmations.discard_edit_media.message": "Habēs mutationēs in descriptionem vel prōspectum medii quae nōn sunt servātae; eas dēmittam?", "confirmations.mute.confirm": "Confutare", "confirmations.reply.confirm": "Respondere", + "disabled_account_banner.account_settings": "Praeferentiae ratiōnis", + "disabled_account_banner.text": "Ratio tua {disabledAccount} debilitata est.", "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.", + "domain_block_modal.you_will_lose_followers": "Omnes sectatores tuī ex hoc servō removēbuntur.", + "domain_block_modal.you_wont_see_posts": "Nuntios aut notificātiōnēs ab usoribus in hōc servō nōn vidēbis.", + "domain_pill.activitypub_like_language": "ActivityPub est velut lingua quam Mastodon cum aliīs sociālibus rētibus loquitur.", + "domain_pill.your_handle": "Tuus nominulus:", + "domain_pill.your_server": "Tua domus digitalis, ubi omnia tua nuntia habitant. Hanc non amas? Servēs trānsferāre potes quōcumque tempore et sectātōrēs tuōs simul addūcere.", + "domain_pill.your_username": "Tuō singulāre id indicium in hōc servō est. Est possibile invenīre usōrēs cum eōdem nōmine in servīs aliīs.", "embed.instructions": "Embed this status on your website by copying the code below.", + "emoji_button.activity": "Actiō", "emoji_button.food": "Cibus et potus", "emoji_button.people": "Homines", "emoji_button.search": "Quaerere...", + "empty_column.account_suspended": "Rātiō suspēnsa", "empty_column.account_timeline": "Hic nulla contributa!", "empty_column.account_unavailable": "Notio non impetrabilis", - "empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}", + "empty_column.blocks": "Nondum quemquam usorem obsēcāvisti.", + "empty_column.direct": "Nōn habēs adhūc ullo mentionēs prīvātās. Cum ūnam mīseris aut accipis, hīc apparēbit.", + "empty_column.followed_tags": "Nōn adhūc aliquem hastāginem secūtus es. Cum id fēceris, hic ostendētur.", + "empty_column.home": "Tua linea temporum domesticus vacua est! Sequere plures personas ut eam compleas.", "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", + "empty_column.lists": "Nōn adhūc habēs ullo tabellās. Cum creās, hīc apparēbunt.", + "empty_column.mutes": "Nondum quemquam usorem tacuisti.", + "empty_column.notification_requests": "Omnia clara sunt! Nihil hic est. Cum novās notificātiōnēs accipīs, hic secundum tua praecepta apparebunt.", + "empty_column.notifications": "Nōn adhūc habēs ullo notificātiōnēs. Cum aliī tē interagunt, hīc videbis.", "explore.trending_statuses": "Contributa", + "filtered_notifications_banner.mentions": "{count, plural, one {mentiō} other {mentiōnēs}}", + "firehose.all": "Omnis", + "footer.about": "De", "generic.saved": "Servavit", + "hashtag.column_settings.tag_mode.all": "Haec omnia", "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "hashtag.counter_by_accounts": "{count, plural, one {{counter} particeps} other {{counter} participēs}}", + "hashtag.counter_by_uses": "{count, plural, one {{counter} nuntius} other {{counter} nuntii}}", + "hashtag.counter_by_uses_today": "{count, plural, one {{counter} nuntius} other {{counter} nuntii}} hodie", + "hashtags.and_other": "…et {count, plural, other {# plus}}", + "intervals.full.days": "{number, plural, one {# die} other {# dies}}", + "intervals.full.hours": "{number, plural, one {# hora} other {# horae}}", + "intervals.full.minutes": "{number, plural, one {# minutum} other {# minuta}}", "keyboard_shortcuts.back": "Re navigare", "keyboard_shortcuts.blocked": "Aperire listam usorum obstructorum", "keyboard_shortcuts.boost": "Inlustrare publicatio", @@ -90,18 +131,47 @@ "keyboard_shortcuts.up": "to move up in the list", "lightbox.close": "Claudere", "lightbox.next": "Secundum", + "lists.account.add": "Adde ad tabellās", + "lists.new.create": "Addere tabella", + "load_pending": "{count, plural, one {# novum item} other {# nova itema}}", + "media_gallery.toggle_visible": "{number, plural, one {Cēla imaginem} other {Cēla imagines}}", + "moved_to_account_banner.text": "Tua ratione {disabledAccount} interdum reposita est, quod ad {movedToAccount} migrāvisti.", + "mute_modal.you_wont_see_mentions": "Non videbis nuntios quī eōs commemorant.", + "navigation_bar.about": "De", "navigation_bar.domain_blocks": "Hidden domains", - "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", + "not_signed_in_indicator.not_signed_in": "Ad hunc locum pervenire oportet ut inīre facias.", + "notification.admin.report": "{name} nuntiavit {target}", + "notification.admin.sign_up": "{name} subscripsit", + "notification.favourite": "{name} nuntium tuum favit", + "notification.follow": "{name} te secutus est", + "notification.follow_request": "{name} postulavit ut te sequeretur", + "notification.mention": "{name} memoravi", + "notification.moderation_warning": "Accepistī monitionem moderationis.", + "notification.moderation_warning.action_disable": "Ratio tua debilitata est.", "notification.moderation_warning.action_none": "Tua ratiō monitum moderātiōnis accēpit.", - "notification.reblog": "{name} boosted your status", + "notification.moderation_warning.action_sensitive": "Tua nuntia hinc sensibiliter notabuntur.", + "notification.moderation_warning.action_silence": "Ratio tua est limitata.", + "notification.moderation_warning.action_suspend": "Ratio tua suspensus est.", + "notification.own_poll": "Suffragium tuum terminatum est.", + "notification.poll": "Electione in quam suffragium dedisti finita est.", + "notification.reblog": "{name} tuum nuntium amplificavit.", + "notification.relationships_severance_event.account_suspension": "Admin ab {from} {target} suspendit, quod significat nōn iam posse tē novitātēs ab eīs accipere aut cum eīs interagere.", + "notification.relationships_severance_event.domain_block": "Admin ab {from} {target} obsēcāvit, includēns {followersCount} ex tuīs sectātōribus et {followingCount, plural, one {# ratione} other {# rationibus}} quās sequeris.", + "notification.relationships_severance_event.user_domain_block": "Bloqueāstī {target}, removēns {followersCount} ex sectātōribus tuīs et {followingCount, plural, one {# rationem} other {# rationēs}} quōs sequeris.", + "notification.status": "{name} nuper publicavit", + "notification.update": "{name} nuntium correxit", + "notification_requests.accept": "Accipe", "notifications.filter.all": "Omnia", "notifications.filter.polls": "Eventus electionis", + "notifications.group": "Notificātiōnēs", "onboarding.actions.go_to_explore": "See what's trending", "onboarding.actions.go_to_home": "Go to your home feed", - "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", + "onboarding.follows.lead": "Tua domus feed est principalis via Mastodon experīrī. Quō plūrēs persōnas sequeris, eō actīvior et interessantior erit. Ad tē incipiendum, ecce quaedam suāsiones:", "onboarding.follows.title": "Popular on Mastodon", - "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", + "onboarding.profile.display_name_hint": "Tuum nomen completum aut tuum nomen ludens...", + "onboarding.start.lead": "Nunc pars es Mastodonis, singularis, socialis medii platformae decentralis ubi—non algorismus—tuam ipsius experientiam curas. Incipiāmus in nova hac socialis regione:", "onboarding.start.skip": "Want to skip right ahead?", + "onboarding.start.title": "Perfecisti eam!", "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", "onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}", "onboarding.steps.publish_status.body": "Say hello to the world.", @@ -109,31 +179,48 @@ "onboarding.steps.setup_profile.title": "Customize your profile", "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", "onboarding.steps.share_profile.title": "Share your profile", - "onboarding.tips.accounts_from_other_servers": "Scisne? Quoniam Mastodon dēcentālis est, nōnnulla profīlia quae invenīs in servīs aliīs quam tuōrum erunt hospitāta. Tamen cum eīs sine impedīmentō interāgere potes! Servus eōrum in alterā parte nōminis eōrum est!", + "onboarding.tips.2fa": "Scisne? Tūam ratiōnem sēcūrāre potes duōrum elementōrum authentīcātiōnem in ratiōnis tuī praeferentiīs statuendō. Cum ūllā app TOTP ex tuā ēlēctiōne operātur, numerus tēlephōnicus necessārius nōn est!", + "onboarding.tips.accounts_from_other_servers": "Scisne? Quoniam Mastodon dēcentrālis est, nōnnulla profīlia quae invenīs in servīs aliīs quam tuōrum erunt hospitāta. Tamen cum eīs sine impedīmentō interāgere potes! Servus eōrum in alterā parte nōminis eōrum est!", "onboarding.tips.migration": "Scisne? Sī sentīs {domain} tibi in futūrō nōn esse optimam servī ēlēctiōnem, ad alium servum Mastodon sine amittendō sectātōribus tuīs migrāre potes. Etiam tuum servum hospitārī potes!", + "onboarding.tips.verification": "Scisne? Tūam ratiōnem verificāre potes iungendō nexum ad prōfīlium Mastodon tuum in propriā pāginā interrētiā et addendō pāginam ad prōfīlium tuum. Nullae pecūniae aut documenta necessāria sunt!", "poll.closed": "Clausum", + "poll.total_people": "{count, plural, one {# persona} other {# personae}}", + "poll.total_votes": "{count, plural, one {# suffragium} other {# suffragia}}", "poll.vote": "Eligere", "poll.voted": "Elegisti hoc responsum", + "poll.votes": "{votes, plural, one {# sufragium} other {# sufragia}}", "poll_button.add_poll": "Addere electionem", "poll_button.remove_poll": "Auferre electionem", "privacy.change": "Adjust status privacy", "privacy.public.short": "Coram publico", + "regeneration_indicator.sublabel": "Tua domus feed praeparātur!", + "relative_time.full.days": "{number, plural, one {# ante die} other {# ante dies}}", + "relative_time.full.hours": "{number, plural, one {# ante horam} other {# ante horas}}", "relative_time.full.just_now": "nunc", + "relative_time.full.minutes": "{number, plural, one {# ante minutum} other {# ante minuta}}", + "relative_time.full.seconds": "{number, plural, one {# ante secundum} other {# ante secunda}}", "relative_time.just_now": "nunc", "relative_time.today": "hodie", + "reply_indicator.attachments": "{count, plural, one {# annexus} other {# annexūs}}", "report.block": "Impedimentum", + "report.block_explanation": "Non videbis eorum nuntios. Non poterunt vidēre tuōs nuntios aut tē sequī. Intelligere poterunt sē obstrūctōs esse.", "report.categories.other": "Altera", "report.category.title_account": "notio", "report.category.title_status": "contributum", "report.close": "Confectum", "report.mute": "Confutare", + "report.mute_explanation": "Non videbis eōrum nuntiōs. Possunt adhuc tē sequī et tuōs nuntiōs vidēre, nec sciēbunt sē tacitōs esse.", "report.next": "Secundum", - "report.placeholder": "Type or paste additional comments", + "report.placeholder": "Commentāriī adiūnctī", "report.submit": "Mittere", "report.target": "Report {target}", - "report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached", + "report_notification.attached_statuses": "{count, plural, one {{count} nuntius} other {{count} nuntii}} attachiatus", "report_notification.categories.other": "Altera", "search.placeholder": "Quaerere", + "search_results.all": "Omnis", + "server_banner.active_users": "Usūrāriī āctīvī", + "server_banner.administered_by": "Administratur:", + "server_banner.introduction": "{domain} pars est de rete sociali decentralizato a {mastodon} propulsato.", "server_banner.learn_more": "Discere plura", "sign_in_banner.sign_in": "Sign in", "status.admin_status": "Open this status in the moderation interface", @@ -143,13 +230,29 @@ "status.delete": "Oblitterare", "status.edit": "Recolere", "status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}", + "status.favourites": "{count, plural, one {favoritum} other {favorita}}", + "status.history.created": "{name} creatum {date}", + "status.history.edited": "{name} correxit {date}", "status.open": "Expand this status", - "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}", + "status.reblogged_by": "{name} adiuvavit", + "status.reblogs": "{count, plural, one {auctus} other {auctūs}}", + "status.title.with_attachments": "{user} publicavit {attachmentCount, plural, one {unum annexum} other {{attachmentCount} annexa}}", "tabs_bar.home": "Domi", + "time_remaining.days": "{number, plural, one {# die} other {# dies}} restant", + "time_remaining.hours": "{number, plural, one {# hora} other {# horae}} restant", + "time_remaining.minutes": "{number, plural, one {# minutum} other {# minuta}} restant", + "time_remaining.seconds": "{number, plural, one {# secundum} other {# secunda}} restant", + "timeline_hint.remote_resource_not_displayed": "{resource} ab aliīs servīs nōn ostenduntur.", "timeline_hint.resources.statuses": "Contributa pristina", - "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}", + "trends.counter_by_accounts": "{count, plural, one {{counter} persōna} other {{counter} persōnae}} in {days, plural, one {diē prīdiē} other {diēbus praeteritīs {days}}}", + "ui.beforeunload": "Si Mastodon discesseris, tua epitome peribit.", + "units.short.billion": "{count} millia milionum", + "units.short.million": "{count} milionum", + "units.short.thousand": "{count} millia", + "upload_button.label": "Imaginēs, vīdeō aut fīle audītūs adde", "upload_form.audio_description": "Describe for people who are hard of hearing", "upload_form.edit": "Recolere", + "upload_modal.description_placeholder": "A velox brunneis vulpes salit super piger canis", "upload_progress.label": "Uploading…", "video.mute": "Confutare soni" } diff --git a/config/locales/devise.la.yml b/config/locales/devise.la.yml index 3a7ba0d445..a6fe5e1e4b 100644 --- a/config/locales/devise.la.yml +++ b/config/locales/devise.la.yml @@ -1 +1,8 @@ +--- la: + devise: + passwords: + send_instructions: Sī adresa tua epistularis in nostra basi datōrum exstat, vinculum ad recuperandam clavem adresa tua epistulari adferētur pauca momenta post. Sī autem hanc epistulam nōn recēpistī, rogāmus ut scrūtināriōnem spurcāriī tuī faciās. + registrations: + destroyed: Vale! Ratio tua succēssu cancellāta est. Spērāmus tē mox iterum vidēre. + signed_up_but_inactive: Te cōnscrīpsistī succēdāneē. At nōn potuimus tē introīre quod ratio* tua nōn adhūc est activāta.* diff --git a/config/locales/doorkeeper.ja.yml b/config/locales/doorkeeper.ja.yml index 62f2a3eb0a..26f7ff5635 100644 --- a/config/locales/doorkeeper.ja.yml +++ b/config/locales/doorkeeper.ja.yml @@ -135,6 +135,7 @@ ja: media: メディアの添付 mutes: ミュート notifications: 通知 + profile: Mastodonのプロフィール push: プッシュ通知 reports: 通報 search: 検索 @@ -165,6 +166,7 @@ ja: admin:write:reports: 通報に対するアクションの実行 crypto: エンドツーエンド暗号化の使用 follow: アカウントのつながりを変更 + profile: アカウントのプロフィール情報の読み取りのみ push: プッシュ通知の受信 read: アカウントのすべてのデータの読み取り read:accounts: アカウント情報の読み取り diff --git a/config/locales/doorkeeper.lad.yml b/config/locales/doorkeeper.lad.yml index b2c140b9c2..c335d67fd6 100644 --- a/config/locales/doorkeeper.lad.yml +++ b/config/locales/doorkeeper.lad.yml @@ -135,6 +135,7 @@ lad: media: Aneksos de multimedia mutes: Silensiasyones notifications: Avizos + profile: Tu profil de Mastodon push: Avizos arrepushados reports: Raportos search: Bushkeda @@ -165,6 +166,7 @@ lad: admin:write:reports: fazer aksyones de moderasyon en raportos crypto: kulanear shifrasyon de lado a lado follow: modifikar relasyones de kuentos + profile: melda solo la informasyon del profil push: risivir tus avizos arrepushados read: meldar todos tus datos de kuento read:accounts: ver enformasyon de kuentos diff --git a/config/locales/doorkeeper.lt.yml b/config/locales/doorkeeper.lt.yml index 5c2e4fd4e0..38bb17ad13 100644 --- a/config/locales/doorkeeper.lt.yml +++ b/config/locales/doorkeeper.lt.yml @@ -135,6 +135,7 @@ lt: media: Medijos priedai mutes: Nutildymai notifications: Pranešimai + profile: Tavo Mastodon profilis push: Tiesioginiai pranešimai reports: Ataskaitos search: Paieška @@ -165,6 +166,7 @@ lt: admin:write:reports: atlikti ataskaitų prižiūrėjimo veiksmus crypto: naudoti visapusį šifravimą follow: modifikuoti paskyros sąryšius + profile: skaityti tik tavo paskyros profilio informaciją push: gauti tiesioginius pranešimus read: skaityti visus paskyros duomenis read:accounts: matyti paskyrų informaciją diff --git a/config/locales/doorkeeper.sv.yml b/config/locales/doorkeeper.sv.yml index f2c8bd34b8..bc4ba6f53e 100644 --- a/config/locales/doorkeeper.sv.yml +++ b/config/locales/doorkeeper.sv.yml @@ -135,6 +135,7 @@ sv: media: Mediabilagor mutes: Tystade användare notifications: Aviseringar + profile: Din Mastodon-profil push: Push-aviseringar reports: Rapporter search: Sök diff --git a/config/locales/doorkeeper.th.yml b/config/locales/doorkeeper.th.yml index 067e065588..b0d0549d1d 100644 --- a/config/locales/doorkeeper.th.yml +++ b/config/locales/doorkeeper.th.yml @@ -135,6 +135,7 @@ th: media: ไฟล์แนบสื่อ mutes: การซ่อน notifications: การแจ้งเตือน + profile: โปรไฟล์ Mastodon ของคุณ push: การแจ้งเตือนแบบผลัก reports: การรายงาน search: ค้นหา @@ -165,6 +166,7 @@ th: admin:write:reports: ทำการกระทำการกลั่นกรองต่อรายงาน crypto: ใช้การเข้ารหัสแบบต้นทางถึงปลายทาง follow: ปรับเปลี่ยนความสัมพันธ์ของบัญชี + profile: อ่านเฉพาะข้อมูลโปรไฟล์ของบัญชีของคุณเท่านั้น push: รับการแจ้งเตือนแบบผลักของคุณ read: อ่านข้อมูลบัญชีทั้งหมดของคุณ read:accounts: ดูข้อมูลบัญชี diff --git a/config/locales/doorkeeper.vi.yml b/config/locales/doorkeeper.vi.yml index 7f1c5430ed..d0bdd2cc7b 100644 --- a/config/locales/doorkeeper.vi.yml +++ b/config/locales/doorkeeper.vi.yml @@ -135,6 +135,7 @@ vi: media: Tập tin đính kèm mutes: Đã ẩn notifications: Thông báo + profile: Hồ sơ Mastodon của bạn push: Thông báo đẩy reports: Báo cáo search: Tìm kiếm @@ -165,6 +166,7 @@ vi: admin:write:reports: áp đặt kiểm duyệt với các báo cáo crypto: dùng mã hóa đầu cuối follow: sửa đổi các mối quan hệ tài khoản + profile: chỉ đọc thông tin tài khoản cơ bản push: nhận thông báo đẩy read: đọc mọi dữ liệu tài khoản read:accounts: xem thông tin tài khoản diff --git a/config/locales/id.yml b/config/locales/id.yml index aae790f481..ac42afdb4f 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -89,6 +89,7 @@ id: moderation: active: Aktif all: Semua + disabled: Nonaktif pending: Tertunda silenced: Terbatas suspended: Disuspen @@ -121,6 +122,8 @@ id: removed_header_msg: Berhasil menghapus gambar header %{username} resend_confirmation: already_confirmed: Pengguna ini sudah dikonfirmasi + send: Kirim ulang email konfirmasi + success: Email konfirmasi berhasil dikirim! reset: Atur ulang reset_password: Reset kata sandi resubscribe: Langganan ulang @@ -128,6 +131,7 @@ id: search: Cari search_same_email_domain: Pengguna lain dengan domain email yang sama search_same_ip: Pengguna lain dengan IP yang sama + security: Keamanan security_measures: only_password: Hanya kata sandi password_and_2fa: Kata sandi dan 2FA @@ -278,6 +282,7 @@ id: update_custom_emoji_html: "%{name} memperbarui emoji %{target}" update_domain_block_html: "%{name} memperbarui blokir domain untuk %{target}" update_ip_block_html: "%{name} mengubah peraturan untuk IP %{target}" + update_report_html: "%{name} memperbarui laporan %{target}" update_status_html: "%{name} memperbarui status %{target}" update_user_role_html: "%{name} mengubah peran %{target}" deleted_account: akun yang dihapus @@ -302,6 +307,7 @@ id: unpublish: Batal terbitkan unpublished_msg: Pengumuman berhasil ditarik! updated_msg: Pengumuman berhasil diperbarui! + critical_update_pending: Pembaruan penting tertunda custom_emojis: assign_category: Beri kategori by_domain: Domain diff --git a/config/locales/la.yml b/config/locales/la.yml index 3a7ba0d445..d3733df934 100644 --- a/config/locales/la.yml +++ b/config/locales/la.yml @@ -1 +1,34 @@ +--- la: + about: + about_mastodon_html: '"Rete sociale futuri: Nullae praebendae, nulla observatio corporativa, ethica designatio, et decentralizatio! Tua data cum Mastodonte posside!"' + contact_missing: Non definitum + contact_unavailable: Nōn Applicābilis + hosted_on: Mastodon in %{domain} hospitātum + title: De + accounts: + follow: Sequere + followers: + one: Sectātor + other: Sectātōrēs + following: Sequendī + instance_actor_flash: Hic ratio est actōr virtuālis ad repraesentandam ipsum servatorem et non ullam individuam usorem. Ad scopōs foederātiōnis ūtor nec suspendendus est. + last_active: Ultimum Actum + link_verified_on: Dominium huius nexūs est comprobatum die %{date}. + nothing_here: Nihil est hic! + pin_errors: + following: Iam debes sequi personam quam vis probare. + posts: + one: Nuntius + other: Nuntii + posts_tab_heading: Nuntii + admin: + account_actions: + action: Agere actionem + title: Actionem moderationis in %{acct} gerere + account_moderation_notes: + create: Relinque nota + created_msg: Nota moderationis feliciter creata est! + destroyed_msg: Nota moderationis feliciter deleta est! + accounts: + are_you_sure: Esne certus? diff --git a/config/locales/nl.yml b/config/locales/nl.yml index a527fdb5a7..328467f483 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1814,14 +1814,14 @@ nl: subject: Jouw archief staat klaar om te worden gedownload title: Archief ophalen failed_2fa: - details: 'Hier zijn details van de inlogpoging:' + details: 'Hier zijn de details van de inlogpoging:' explanation: Iemand heeft geprobeerd om in te loggen op jouw account maar heeft een ongeldige tweede verificatiefactor opgegeven. further_actions_html: Als jij dit niet was, raden we je aan om onmiddellijk %{action} aangezien het in gevaar kan zijn. subject: Tweestapsverificatiefout title: Tweestapsverificatie mislukt suspicious_sign_in: change_password: je wachtwoord te wijzigen - details: 'Hier zijn de details van inlogpoging:' + details: 'Hier zijn de details van het inloggen:' explanation: We hebben vastgesteld dat iemand vanaf een nieuw IP-adres op jouw account is ingelogd. further_actions_html: Wanneer jij dit niet was, adviseren wij om onmiddellijk %{action} en om tweestapsverificatie in te schakelen, om zo je account veilig te houden. subject: Jouw account is vanaf een nieuw IP-adres benaderd diff --git a/config/locales/simple_form.id.yml b/config/locales/simple_form.id.yml index 856f312eda..1f493435e8 100644 --- a/config/locales/simple_form.id.yml +++ b/config/locales/simple_form.id.yml @@ -2,6 +2,9 @@ id: simple_form: hints: + account: + discoverable: Postingan dan profil publik Anda mungkin ditampilkan atau direkomendasikan di berbagai area Mastodon dan profil Anda mungkin disarankan ke pengguna lain. + display_name: Nama lengkap Anda atau nama lucu Anda. account_alias: acct: Tentukan namapengguna@domain akun yang ingin Anda pindah account_migration: diff --git a/config/locales/th.yml b/config/locales/th.yml index bafcd30dee..d1359e0176 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -1837,11 +1837,13 @@ th: edit_profile_title: ปรับแต่งโปรไฟล์ของคุณ explanation: นี่คือเคล็ดลับบางส่วนที่จะช่วยให้คุณเริ่มต้นใช้งาน feature_action: เรียนรู้เพิ่มเติม - feature_audience: Mastodon มีความพิเศษที่ให้คุณจัดการผู้รับสารของคุณได้โดยไม่มีตัวกลาง นอกจากนี้ การติดตั้ง Mastodon บนโครงสร้างพื้นฐานของคุณจะทำให้คุณสามารถติดตาม (และติดตามโดย) เซิร์ฟเวอร์ Mastodon แห่งไหนก็ได้ที่ทำงานอยู่ โดยไม่มีใครสามารถควบคุมได้นอกจากคุณ + feature_audience: Mastodon ให้ความเป็นไปได้ที่เป็นเอกลักษณ์แก่คุณในการจัดการผู้ชมของคุณโดยไม่มีตัวกลาง Mastodon ที่ปรับใช้ในโครงสร้างพื้นฐานของคุณเองอนุญาตให้คุณติดตามและได้รับการติดตามจากเซิร์ฟเวอร์ Mastodon อื่นใดทางออนไลน์และไม่อยู่ภายใต้การควบคุมของใครนอกจากคุณ feature_audience_title: สร้างผู้ชมของคุณด้วยความมั่นใจ feature_control: คุณทราบดีที่สุดถึงสิ่งที่คุณต้องการเห็นในฟีดหน้าแรกของคุณ ไม่มีอัลกอริทึมหรือโฆษณาให้เสียเวลาของคุณ ติดตามใครก็ตามทั่วทั้งเซิร์ฟเวอร์ Mastodon ใด ๆ จากบัญชีเดียวและรับโพสต์ของเขาตามลำดับเวลา และทำให้มุมอินเทอร์เน็ตของคุณเป็นเหมือนคุณมากขึ้นอีกนิด feature_control_title: การควบคุมเส้นเวลาของคุณเอง + feature_creativity: Mastodon รองรับโพสต์เสียง วิดีโอ และรูปภาพ, คำอธิบายการช่วยการเข้าถึง, การสำรวจความคิดเห็น, คำเตือนเนื้อหา, ภาพประจำตัวแบบเคลื่อนไหว, อีโมจิที่กำหนดเอง, การควบคุมการครอบตัดภาพขนาดย่อ และอื่น ๆ เพื่อช่วยให้คุณแสดงออกตัวคุณเองทางออนไลน์ ไม่ว่าคุณกำลังจะเผยแพร่ศิลปะของคุณ, เพลงของคุณ หรือพอดแคสต์ของคุณ Mastodon อยู่ที่นั่นเพื่อคุณ feature_creativity_title: ความคิดสร้างสรรค์ที่ไม่มีใครเทียบได้ + feature_moderation: Mastodon นำการตัดสินใจกลับมาอยู่ในมือของคุณ แต่ละเซิร์ฟเวอร์สร้างกฎและระเบียบข้อบังคับของตนเอง ซึ่งบังคับใช้ในเซิร์ฟเวอร์และไม่ใช่จากบนลงล่างเหมือนสื่อสังคมขององค์กร ทำให้สื่อสังคมยืดหยุ่นมากที่สุดในการตอบสนองต่อความต้องการของกลุ่มคนที่แตกต่างกัน เข้าร่วมเซิร์ฟเวอร์ที่มีกฎที่คุณเห็นด้วย หรือโฮสต์ของคุณเอง feature_moderation_title: การกลั่นกรองในแบบที่ควรจะเป็น follow_action: ติดตาม follow_step: การติดตามผู้คนที่น่าสนใจคือสิ่งที่ Mastodon ให้ความสำคัญ From f0f144e96da62718e849a8dd5cd55ddbc03763ab Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Mon, 10 Jun 2024 23:47:59 +0900 Subject: [PATCH 362/658] Add `customManagers:dockerfileVersions` to renovate.json5 (#30607) --- .github/renovate.json5 | 1 + Dockerfile | 2 ++ streaming/Dockerfile | 1 + 3 files changed, 4 insertions(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 52f7c63e5b..2cf7bec8ee 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -2,6 +2,7 @@ $schema: 'https://docs.renovatebot.com/renovate-schema.json', extends: [ 'config:recommended', + 'customManagers:dockerfileVersions', ':labels(dependencies)', ':prConcurrentLimitNone', // Remove limit for open PRs at any time. ':prHourlyLimit2', // Rate limit PR creation to a maximum of two per hour. diff --git a/Dockerfile b/Dockerfile index 09aa8f2ddb..cb5b872059 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,8 +11,10 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} # Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"] +# renovate: datasource=docker depName=docker.io/ruby ARG RUBY_VERSION="3.3.2" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] +# renovate: datasource=node-version depName=node ARG NODE_MAJOR_VERSION="20" # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] ARG DEBIAN_VERSION="bookworm" diff --git a/streaming/Dockerfile b/streaming/Dockerfile index 7f373e9cd5..564e717a40 100644 --- a/streaming/Dockerfile +++ b/streaming/Dockerfile @@ -8,6 +8,7 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] +# renovate: datasource=node-version depName=node ARG NODE_MAJOR_VERSION="20" # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] ARG DEBIAN_VERSION="bookworm" From 28f9a8f2ecabb0c087e27522217b78da732611c2 Mon Sep 17 00:00:00 2001 From: Daniel M Brasil Date: Mon, 10 Jun 2024 11:52:33 -0300 Subject: [PATCH 363/658] Add Specs for Scheduled Status Model Validations (#30585) --- spec/models/scheduled_status_spec.rb | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 spec/models/scheduled_status_spec.rb diff --git a/spec/models/scheduled_status_spec.rb b/spec/models/scheduled_status_spec.rb new file mode 100644 index 0000000000..15031a5895 --- /dev/null +++ b/spec/models/scheduled_status_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ScheduledStatus do + let(:account) { Fabricate(:account) } + + describe 'validations' do + context 'when scheduled_at is less than minimum offset' do + subject { Fabricate.build(:scheduled_status, scheduled_at: 4.minutes.from_now, account: account) } + + it 'is not valid', :aggregate_failures do + expect(subject).to_not be_valid + expect(subject.errors[:scheduled_at]).to include(I18n.t('scheduled_statuses.too_soon')) + end + end + + context 'when account has reached total limit' do + subject { Fabricate.build(:scheduled_status, account: account) } + + before do + allow(account.scheduled_statuses).to receive(:count).and_return(described_class::TOTAL_LIMIT) + end + + it 'is not valid', :aggregate_failures do + expect(subject).to_not be_valid + expect(subject.errors[:base]).to include(I18n.t('scheduled_statuses.over_total_limit', limit: ScheduledStatus::TOTAL_LIMIT)) + end + end + + context 'when account has reached daily limit' do + subject { Fabricate.build(:scheduled_status, account: account, scheduled_at: base_time + 10.minutes) } + + let(:base_time) { Time.current.change(hour: 12) } + + before do + stub_const('ScheduledStatus::DAILY_LIMIT', 3) + + travel_to base_time do + Fabricate.times(ScheduledStatus::DAILY_LIMIT, :scheduled_status, account: account, scheduled_at: base_time + 1.hour) + end + end + + it 'is not valid', :aggregate_failures do + expect(subject).to_not be_valid + expect(subject.errors[:base]).to include(I18n.t('scheduled_statuses.over_daily_limit', limit: ScheduledStatus::DAILY_LIMIT)) + end + end + end +end From 92b3004bf31d91c94efae4957234a36aef10da59 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 10 Jun 2024 11:03:41 -0400 Subject: [PATCH 364/658] Reference constants from account validation specs (#30634) --- spec/models/account_spec.rb | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 2c5df198d9..225929ae39 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -768,20 +768,20 @@ RSpec.describe Account do expect(account).to model_have_error_on_field(:username) end - it 'is invalid if the username is longer than 30 characters' do - account = Fabricate.build(:account, username: Faker::Lorem.characters(number: 31)) + it 'is invalid if the username is longer than the character limit' do + account = Fabricate.build(:account, username: username_over_limit) account.valid? expect(account).to model_have_error_on_field(:username) end - it 'is invalid if the display name is longer than 30 characters' do - account = Fabricate.build(:account, display_name: Faker::Lorem.characters(number: 31)) + it 'is invalid if the display name is longer than the character limit' do + account = Fabricate.build(:account, display_name: username_over_limit) account.valid? expect(account).to model_have_error_on_field(:display_name) end - it 'is invalid if the note is longer than 500 characters' do - account = Fabricate.build(:account, note: Faker::Lorem.characters(number: 501)) + it 'is invalid if the note is longer than the character limit' do + account = Fabricate.build(:account, note: account_note_over_limit) account.valid? expect(account).to model_have_error_on_field(:note) end @@ -814,24 +814,32 @@ RSpec.describe Account do expect(account).to model_have_error_on_field(:username) end - it 'is valid even if the username is longer than 30 characters' do - account = Fabricate.build(:account, domain: 'domain', username: Faker::Lorem.characters(number: 31)) + it 'is valid even if the username is longer than the character limit' do + account = Fabricate.build(:account, domain: 'domain', username: username_over_limit) account.valid? expect(account).to_not model_have_error_on_field(:username) end - it 'is valid even if the display name is longer than 30 characters' do - account = Fabricate.build(:account, domain: 'domain', display_name: Faker::Lorem.characters(number: 31)) + it 'is valid even if the display name is longer than the character limit' do + account = Fabricate.build(:account, domain: 'domain', display_name: username_over_limit) account.valid? expect(account).to_not model_have_error_on_field(:display_name) end - it 'is valid even if the note is longer than 500 characters' do - account = Fabricate.build(:account, domain: 'domain', note: Faker::Lorem.characters(number: 501)) + it 'is valid even if the note is longer than the character limit' do + account = Fabricate.build(:account, domain: 'domain', note: account_note_over_limit) account.valid? expect(account).to_not model_have_error_on_field(:note) end end + + def username_over_limit + 'a' * described_class::USERNAME_LENGTH_LIMIT * 2 + end + + def account_note_over_limit + 'a' * described_class::NOTE_LENGTH_LIMIT * 2 + end end describe 'scopes' do From 3e3f3d75805ec4209e0b12984626a5be0a9ba2e5 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 10 Jun 2024 11:04:01 -0400 Subject: [PATCH 365/658] Match report validation spec to extracted constant (#30633) --- spec/models/report_spec.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb index 0168268bcb..d01d37bd8b 100644 --- a/spec/models/report_spec.rb +++ b/spec/models/report_spec.rb @@ -123,14 +123,14 @@ describe Report do describe 'validations' do let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } - it 'is invalid if comment is longer than 1000 characters only if reporter is local' do - report = Fabricate.build(:report, comment: Faker::Lorem.characters(number: 1001)) + it 'is invalid if comment is longer than character limit and reporter is local' do + report = Fabricate.build(:report, comment: comment_over_limit) expect(report.valid?).to be false expect(report).to model_have_error_on_field(:comment) end - it 'is valid if comment is longer than 1000 characters and reporter is not local' do - report = Fabricate.build(:report, account: remote_account, comment: Faker::Lorem.characters(number: 1001)) + it 'is valid if comment is longer than character limit and reporter is not local' do + report = Fabricate.build(:report, account: remote_account, comment: comment_over_limit) expect(report.valid?).to be true end @@ -146,5 +146,9 @@ describe Report do expect(report.valid?).to be false expect(report).to model_have_error_on_field(:rule_ids) end + + def comment_over_limit + 'a' * described_class::COMMENT_SIZE_LIMIT * 2 + end end end From 28921a12fe0033c7231f42e95a2be80628844bb4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 10 Jun 2024 11:22:26 -0400 Subject: [PATCH 366/658] Update macOS local dev setup instructions (#30641) --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f807120c1e..4aca37673b 100644 --- a/README.md +++ b/README.md @@ -86,18 +86,18 @@ A **Vagrant** configuration is included for development purposes. To use it, com - Run `vagrant ssh -c "cd /vagrant && bin/dev"` - Open `http://mastodon.local` in your browser -### MacOS +### macOS -To set up **MacOS** for native development, complete the following steps: +To set up **macOS** for native development, complete the following steps: -- Use a Ruby version manager to install the specified version from `.ruby-version` -- Run `bundle` to install required gems -- Run `brew install postgresql@14 redis imagemagick libidn` to install required dependencies -- Navigate to Mastodon's root directory and run `brew install nvm` then `nvm use` to use the version from `.nvmrc` -- Run `yarn` to install required packages -- Run `corepack enable && corepack prepare` -- Run `RAILS_ENV=development bundle exec rails db:setup` -- Finally, run `bin/dev` which will launch the local services via `overmind` (if installed) or `foreman` +- Install [Homebrew] and run `brew install postgresql@14 redis imagemagick +libidn nvm` to install the required project dependencies +- Use a Ruby version manager to activate the ruby in `.ruby-version` and run + `nvm use` to activate the node version from `.nvmrc` +- Run the `bin/setup` script, which will install the required ruby gems and node + packages and prepare the database for local development +- Finally, run the `bin/dev` script which will launch services via `overmind` + (if installed) or `foreman` ### Docker @@ -155,3 +155,4 @@ You should have received a copy of the GNU Affero General Public License along w [Development Containers]: https://containers.dev/supporting [Docker]: https://docs.docker.com [GitHub Codespaces]: https://docs.github.com/en/codespaces +[Homebrew]: https://brew.sh From 9bf2e2eda0ffea6382e161f7ebb43d73aaf658ca Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 10 Jun 2024 11:23:17 -0400 Subject: [PATCH 367/658] Extract `TEXT_LENGTH_LIMIT` constant in `Appeal` class (#30638) --- app/models/appeal.rb | 4 +++- spec/models/appeal_spec.rb | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/models/appeal.rb b/app/models/appeal.rb index 395056b76f..fafa75e69d 100644 --- a/app/models/appeal.rb +++ b/app/models/appeal.rb @@ -18,6 +18,8 @@ class Appeal < ApplicationRecord MAX_STRIKE_AGE = 20.days + TEXT_LENGTH_LIMIT = 2_000 + belongs_to :account belongs_to :strike, class_name: 'AccountWarning', foreign_key: 'account_warning_id', inverse_of: :appeal @@ -26,7 +28,7 @@ class Appeal < ApplicationRecord belongs_to :rejected_by_account end - validates :text, presence: true, length: { maximum: 2_000 } + validates :text, presence: true, length: { maximum: TEXT_LENGTH_LIMIT } validates :account_warning_id, uniqueness: true validate :validate_time_frame, on: :create diff --git a/spec/models/appeal_spec.rb b/spec/models/appeal_spec.rb index 12373a9494..13ca3a2d90 100644 --- a/spec/models/appeal_spec.rb +++ b/spec/models/appeal_spec.rb @@ -3,6 +3,19 @@ require 'rails_helper' describe Appeal do + describe 'Validations' do + it 'validates text length is under limit' do + appeal = Fabricate.build( + :appeal, + strike: Fabricate(:account_warning), + text: 'a' * described_class::TEXT_LENGTH_LIMIT * 2 + ) + + expect(appeal).to_not be_valid + expect(appeal).to model_have_error_on_field(:text) + end + end + describe 'scopes' do describe 'approved' do let(:approved_appeal) { Fabricate(:appeal, approved_at: 10.days.ago) } From 9cc4040308a758d4b77961f4da79cf63a044fffe Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 10 Jun 2024 11:23:55 -0400 Subject: [PATCH 368/658] Extract `COMMENT_SIZE_LIMIT` constant in `AP::Activity::Flag` class (#30637) --- app/lib/activitypub/activity/flag.rb | 4 +++- spec/lib/activitypub/activity/flag_spec.rb | 12 +++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/lib/activitypub/activity/flag.rb b/app/lib/activitypub/activity/flag.rb index 68ee43d0eb..b7a412485c 100644 --- a/app/lib/activitypub/activity/flag.rb +++ b/app/lib/activitypub/activity/flag.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ActivityPub::Activity::Flag < ActivityPub::Activity + COMMENT_SIZE_LIMIT = 5000 + def perform return if skip_reports? @@ -38,6 +40,6 @@ class ActivityPub::Activity::Flag < ActivityPub::Activity end def report_comment - (@json['content'] || '')[0...5000] + (@json['content'] || '')[0...COMMENT_SIZE_LIMIT] end end diff --git a/spec/lib/activitypub/activity/flag_spec.rb b/spec/lib/activitypub/activity/flag_spec.rb index 8593d567f4..426cd97df9 100644 --- a/spec/lib/activitypub/activity/flag_spec.rb +++ b/spec/lib/activitypub/activity/flag_spec.rb @@ -54,7 +54,7 @@ RSpec.describe ActivityPub::Activity::Flag do }.with_indifferent_access, sender) end - let(:long_comment) { Faker::Lorem.characters(number: 6000) } + let(:long_comment) { 'a' * described_class::COMMENT_SIZE_LIMIT * 2 } before do subject.perform @@ -63,10 +63,12 @@ RSpec.describe ActivityPub::Activity::Flag do it 'creates a report but with a truncated comment' do report = Report.find_by(account: sender, target_account: flagged) - expect(report).to_not be_nil - expect(report.comment.length).to eq 5000 - expect(report.comment).to eq long_comment[0...5000] - expect(report.status_ids).to eq [status.id] + expect(report) + .to be_present + .and have_attributes(status_ids: [status.id]) + expect(report.comment) + .to have_attributes(length: described_class::COMMENT_SIZE_LIMIT) + .and eq(long_comment[0...described_class::COMMENT_SIZE_LIMIT]) end end From 0e1110c947caf31ae650c73ef35adedebc16b28a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 10 Jun 2024 16:08:04 -0400 Subject: [PATCH 369/658] Use `SECRET_KEY_BASE_DUMMY` feature as placeholder during asset compilation (#30505) --- .github/workflows/test-ruby.yml | 6 +----- Dockerfile | 6 +----- config/environments/production.rb | 6 +++++- config/initializers/active_record_encryption.rb | 5 +++++ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 5f2297381a..8f05dcab3e 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -28,11 +28,7 @@ jobs: env: RAILS_ENV: ${{ matrix.mode }} BUNDLE_WITH: ${{ matrix.mode }} - ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: precompile_placeholder - ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: precompile_placeholder - ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: precompile_placeholder - OTP_SECRET: precompile_placeholder - SECRET_KEY_BASE: precompile_placeholder + SECRET_KEY_BASE_DUMMY: 1 steps: - uses: actions/checkout@v4 diff --git a/Dockerfile b/Dockerfile index cb5b872059..2dc7602b2d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -212,11 +212,7 @@ ARG TARGETPLATFORM RUN \ # Use Ruby on Rails to create Mastodon assets - ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=precompile_placeholder \ - ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=precompile_placeholder \ - ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=precompile_placeholder \ - OTP_SECRET=precompile_placeholder \ - SECRET_KEY_BASE=precompile_placeholder \ + SECRET_KEY_BASE_DUMMY=1 \ bundle exec rails assets:precompile; \ # Cleanup temporary files rm -fr /opt/mastodon/tmp; diff --git a/config/environments/production.rb b/config/environments/production.rb index a39843e956..6686a23d60 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -156,7 +156,11 @@ Rails.application.configure do } # TODO: Remove once devise-two-factor data migration complete - config.x.otp_secret = ENV.fetch('OTP_SECRET') + config.x.otp_secret = if ENV['SECRET_KEY_BASE_DUMMY'] + SecureRandom.hex(64) + else + ENV.fetch('OTP_SECRET') + end # Enable DNS rebinding protection and other `Host` header attacks. # config.hosts = [ diff --git a/config/initializers/active_record_encryption.rb b/config/initializers/active_record_encryption.rb index 900f3c68f0..a83ca80765 100644 --- a/config/initializers/active_record_encryption.rb +++ b/config/initializers/active_record_encryption.rb @@ -5,6 +5,11 @@ ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY ).each do |key| + if ENV['SECRET_KEY_BASE_DUMMY'] + # Use placeholder value during production env asset compilation + ENV[key] = SecureRandom.hex(64) + end + value = ENV.fetch(key) do abort <<~MESSAGE From ef23abcf617813901e34c5dd9587ef7c88fd754d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 08:55:30 +0200 Subject: [PATCH 370/658] chore(deps): update dependency aws-sdk-s3 to v1.152.1 (#30643) 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 4d16fea47c..984bc32d49 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,7 +109,7 @@ GEM aws-sdk-kms (1.83.0) aws-sdk-core (~> 3, >= 3.197.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.152.0) + aws-sdk-s3 (1.152.1) aws-sdk-core (~> 3, >= 3.197.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) From cfd4823b65cc91e758ac9d6d97e367b19ca35691 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 02:57:09 -0400 Subject: [PATCH 371/658] Use fabricator in follow_spec (#30642) --- spec/models/follow_spec.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/spec/models/follow_spec.rb b/spec/models/follow_spec.rb index c7743183cc..9aa172b2f2 100644 --- a/spec/models/follow_spec.rb +++ b/spec/models/follow_spec.rb @@ -36,16 +36,15 @@ RSpec.describe Follow do end end - describe 'recent' do - it 'sorts so that more recent follows comes earlier' do - follow0 = described_class.create!(account: alice, target_account: bob) - follow1 = described_class.create!(account: bob, target_account: alice) + describe '.recent' do + let!(:follow_earlier) { Fabricate(:follow) } + let!(:follow_later) { Fabricate(:follow) } - a = described_class.recent.to_a + it 'sorts with most recent follows first' do + results = described_class.recent - expect(a.size).to eq 2 - expect(a[0]).to eq follow1 - expect(a[1]).to eq follow0 + expect(results.size).to eq 2 + expect(results).to eq [follow_later, follow_earlier] end end From 0dabda9beec11706fbef8cbf8a141266cc69590c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:14:52 +0200 Subject: [PATCH 372/658] New Crowdin Translations (automated) (#30646) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ar.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 68e32dd2aa..6d67d354b6 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -225,7 +225,11 @@ "domain_pill.their_username": "مُعرّفُهم الفريد على الخادم. من الممكن العثور على مستخدمين بنفس اسم المستخدم على خوادم مختلفة.", "domain_pill.username": "اسم المستخدم", "domain_pill.whats_in_a_handle": "ما المقصود بالمُعرِّف؟", + "domain_pill.who_they_are": "بما أن المعالجات تقول من هو الشخص ومكان وجوده، يمكنك التفاعل مع الناس عبر الشبكة الاجتماعية لـ .", + "domain_pill.who_you_are": "لأن معالجتك تقول من أنت ومكان وجودك، يمكن الناس التفاعل معك عبر الشبكة الاجتماعية لـ .", "domain_pill.your_handle": "عنوانك الكامل:", + "domain_pill.your_server": "منزلك الرقمي، حيث تعيش جميع مشاركاتك. لا تحب هذا؟ إنقل الخوادم في أي وقت واخضر متابعينك أيضًا.", + "domain_pill.your_username": "معرفك الفريد على هذا الخادم. من الممكن العثور على مستخدمين بنفس إسم المستخدم على خوادم مختلفة.", "embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.", "embed.preview": "إليك ما سيبدو عليه:", "emoji_button.activity": "الأنشطة", @@ -262,6 +266,7 @@ "empty_column.list": "هذه القائمة فارغة مؤقتا و لكن سوف تمتلئ تدريجيا عندما يبدأ الأعضاء المُنتَمين إليها بنشر منشورات.", "empty_column.lists": "ليس عندك أية قائمة بعد. سوف تظهر قوائمك هنا إن قمت بإنشاء واحدة.", "empty_column.mutes": "لم تقم بكتم أي مستخدم بعد.", + "empty_column.notification_requests": "لا يوجد شيء هنا. عندما تتلقى إشعارات جديدة، سوف تظهر هنا وفقًا لإعداداتك.", "empty_column.notifications": "لم تتلق أي إشعار بعدُ. تفاعل مع المستخدمين الآخرين لإنشاء محادثة.", "empty_column.public": "لا يوجد أي شيء هنا! قم بنشر شيء ما للعامة، أو اتبع المستخدمين الآخرين المتواجدين على الخوادم الأخرى لملء خيط المحادثات", "error.unexpected_crash.explanation": "نظرا لوجود خطأ في التعليمات البرمجية أو مشكلة توافق مع المتصفّح، تعذر عرض هذه الصفحة بشكل صحيح.", @@ -292,6 +297,8 @@ "filter_modal.select_filter.subtitle": "استخدم فئة موجودة أو قم بإنشاء فئة جديدة", "filter_modal.select_filter.title": "تصفية هذا المنشور", "filter_modal.title.status": "تصفية منشور", + "filtered_notifications_banner.mentions": "{count, plural, one {إشارة} two {إشارتين} few {# إشارات} other {# إشارة}}", + "filtered_notifications_banner.pending_requests": "إشعارات من {count, plural, zero {}=0 {لا أحد} one {شخص واحد قد تعرفه} two {شخصين قد تعرفهما} few {# أشخاص قد تعرفهم} many {# شخص قد تعرفهم} other {# شخص قد تعرفهم}}", "filtered_notifications_banner.title": "الإشعارات المصفاة", "firehose.all": "الكل", "firehose.local": "هذا الخادم", @@ -301,6 +308,8 @@ "follow_requests.unlocked_explanation": "حتى وإن كان حسابك غير مقفل، يعتقد فريق {domain} أنك قد ترغب في مراجعة طلبات المتابعة من هذه الحسابات يدوياً.", "follow_suggestions.curated_suggestion": "اختيار الموظفين", "follow_suggestions.dismiss": "لا تُظهرها مجدّدًا", + "follow_suggestions.featured_longer": "مختار يدوياً من قِبل فريق {domain}", + "follow_suggestions.friends_of_friends_longer": "مشهور بين الأشخاص الذين تتابعهم", "follow_suggestions.hints.featured": "تم اختيار هذا الملف الشخصي يدوياً من قبل فريق {domain}.", "follow_suggestions.hints.friends_of_friends": "هذا الملف الشخصي مشهور بين الأشخاص الذين تتابعهم.", "follow_suggestions.hints.most_followed": "هذا الملف الشخصي هو واحد من الأكثر متابعة على {domain}.", @@ -405,6 +414,7 @@ "limited_account_hint.action": "إظهار الملف التعريفي على أي حال", "limited_account_hint.title": "تم إخفاء هذا الملف الشخصي من قبل مشرفي {domain}.", "link_preview.author": "مِن {name}", + "link_preview.more_from_author": "المزيد من {name}", "lists.account.add": "أضف إلى القائمة", "lists.account.remove": "احذف من القائمة", "lists.delete": "احذف القائمة", @@ -465,10 +475,13 @@ "notification.follow_request": "لقد طلب {name} متابعتك", "notification.mention": "{name} ذكرك", "notification.moderation-warning.learn_more": "اعرف المزيد", + "notification.moderation_warning": "لقد تلقيت تحذيرًا بالإشراف", + "notification.moderation_warning.action_delete_statuses": "تم إزالة بعض مشاركاتك.", "notification.moderation_warning.action_disable": "تم تعطيل حسابك.", "notification.moderation_warning.action_mark_statuses_as_sensitive": "بعض من منشوراتك تم تصنيفها على أنها حساسة.", "notification.moderation_warning.action_none": "لقد تلقى حسابك تحذيرا بالإشراف.", "notification.moderation_warning.action_sensitive": "سيتم وضع علامة على منشوراتك على أنها حساسة من الآن فصاعدا.", + "notification.moderation_warning.action_silence": "لقد تم تقييد حسابك.", "notification.moderation_warning.action_suspend": "لقد تم تعليق حسابك.", "notification.own_poll": "انتهى استطلاعك للرأي", "notification.poll": "لقد انتهى استطلاع رأي شاركتَ فيه", From b2496177e00af2b9ce73b378233b2ef3de14cbe4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 03:35:30 -0400 Subject: [PATCH 373/658] Use correct params in `v1/admin/domain_allows` spec (#30378) --- spec/requests/api/v1/admin/domain_allows_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/v1/admin/domain_allows_spec.rb b/spec/requests/api/v1/admin/domain_allows_spec.rb index 662a8f9a8d..b8f0b0055c 100644 --- a/spec/requests/api/v1/admin/domain_allows_spec.rb +++ b/spec/requests/api/v1/admin/domain_allows_spec.rb @@ -113,7 +113,7 @@ RSpec.describe 'Domain Allows' do end context 'with invalid domain name' do - let(:params) { 'foo bar' } + let(:params) { { domain: 'foo bar' } } it 'returns http unprocessable entity' do subject From edf6d64eebdf4c1651f09c0e314d46b7436b46df Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 03:36:46 -0400 Subject: [PATCH 374/658] Use correct params in `settings/preferences/appearance` spec (#30379) --- .../settings/preferences/appearance_controller_spec.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/controllers/settings/preferences/appearance_controller_spec.rb b/spec/controllers/settings/preferences/appearance_controller_spec.rb index 261c426acb..84b8277250 100644 --- a/spec/controllers/settings/preferences/appearance_controller_spec.rb +++ b/spec/controllers/settings/preferences/appearance_controller_spec.rb @@ -23,8 +23,11 @@ describe Settings::Preferences::AppearanceController do end describe 'PUT #update' do + subject { put :update, params: { user: { settings_attributes: { theme: 'contrast' } } } } + it 'redirects correctly' do - put :update, params: { user: { setting_theme: 'contrast' } } + expect { subject } + .to change { user.reload.settings.theme }.to('contrast') expect(response).to redirect_to(settings_preferences_appearance_path) end From 88cfc4056de1f7ab86011eb80b904cd9cd6dc754 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 03:42:15 -0400 Subject: [PATCH 375/658] Extract method to generate series of days in measure sql classes (#29928) --- .../admin/metrics/measure/instance_accounts_measure.rb | 2 +- .../admin/metrics/measure/instance_followers_measure.rb | 2 +- app/lib/admin/metrics/measure/instance_follows_measure.rb | 2 +- .../metrics/measure/instance_media_attachments_measure.rb | 2 +- app/lib/admin/metrics/measure/instance_reports_measure.rb | 2 +- .../admin/metrics/measure/instance_statuses_measure.rb | 2 +- app/lib/admin/metrics/measure/new_users_measure.rb | 2 +- app/lib/admin/metrics/measure/opened_reports_measure.rb | 2 +- app/lib/admin/metrics/measure/query_helper.rb | 8 ++++++++ app/lib/admin/metrics/measure/resolved_reports_measure.rb | 2 +- app/lib/admin/metrics/measure/tag_servers_measure.rb | 2 +- 11 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/lib/admin/metrics/measure/instance_accounts_measure.rb b/app/lib/admin/metrics/measure/instance_accounts_measure.rb index 3d081fdd90..746780ee77 100644 --- a/app/lib/admin/metrics/measure/instance_accounts_measure.rb +++ b/app/lib/admin/metrics/measure/instance_accounts_measure.rb @@ -43,7 +43,7 @@ class Admin::Metrics::Measure::InstanceAccountsMeasure < Admin::Metrics::Measure SELECT count(*) FROM new_accounts ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/instance_followers_measure.rb b/app/lib/admin/metrics/measure/instance_followers_measure.rb index 378c6754d9..0693d5a64a 100644 --- a/app/lib/admin/metrics/measure/instance_followers_measure.rb +++ b/app/lib/admin/metrics/measure/instance_followers_measure.rb @@ -44,7 +44,7 @@ class Admin::Metrics::Measure::InstanceFollowersMeasure < Admin::Metrics::Measur SELECT count(*) FROM new_followers ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/instance_follows_measure.rb b/app/lib/admin/metrics/measure/instance_follows_measure.rb index e213348fbc..90d3819358 100644 --- a/app/lib/admin/metrics/measure/instance_follows_measure.rb +++ b/app/lib/admin/metrics/measure/instance_follows_measure.rb @@ -44,7 +44,7 @@ class Admin::Metrics::Measure::InstanceFollowsMeasure < Admin::Metrics::Measure: SELECT count(*) FROM new_follows ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb b/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb index 1d2dbbe414..89f8b41497 100644 --- a/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb +++ b/app/lib/admin/metrics/measure/instance_media_attachments_measure.rb @@ -53,7 +53,7 @@ class Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure < Admin::Metrics: SELECT COALESCE(SUM(size), 0) FROM new_media_attachments ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/instance_reports_measure.rb b/app/lib/admin/metrics/measure/instance_reports_measure.rb index 9da3d53e34..5f58387a64 100644 --- a/app/lib/admin/metrics/measure/instance_reports_measure.rb +++ b/app/lib/admin/metrics/measure/instance_reports_measure.rb @@ -44,7 +44,7 @@ class Admin::Metrics::Measure::InstanceReportsMeasure < Admin::Metrics::Measure: SELECT count(*) FROM new_reports ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/instance_statuses_measure.rb b/app/lib/admin/metrics/measure/instance_statuses_measure.rb index b918a30a57..5873c6e71f 100644 --- a/app/lib/admin/metrics/measure/instance_statuses_measure.rb +++ b/app/lib/admin/metrics/measure/instance_statuses_measure.rb @@ -45,7 +45,7 @@ class Admin::Metrics::Measure::InstanceStatusesMeasure < Admin::Metrics::Measure SELECT count(*) FROM new_statuses ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/new_users_measure.rb b/app/lib/admin/metrics/measure/new_users_measure.rb index 6837c14c82..32057154d6 100644 --- a/app/lib/admin/metrics/measure/new_users_measure.rb +++ b/app/lib/admin/metrics/measure/new_users_measure.rb @@ -32,7 +32,7 @@ class Admin::Metrics::Measure::NewUsersMeasure < Admin::Metrics::Measure::BaseMe SELECT count(*) FROM new_users ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/opened_reports_measure.rb b/app/lib/admin/metrics/measure/opened_reports_measure.rb index c395c46341..47de38bbe6 100644 --- a/app/lib/admin/metrics/measure/opened_reports_measure.rb +++ b/app/lib/admin/metrics/measure/opened_reports_measure.rb @@ -32,7 +32,7 @@ class Admin::Metrics::Measure::OpenedReportsMeasure < Admin::Metrics::Measure::B SELECT count(*) FROM new_reports ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/query_helper.rb b/app/lib/admin/metrics/measure/query_helper.rb index 969065f73f..5969a96ba9 100644 --- a/app/lib/admin/metrics/measure/query_helper.rb +++ b/app/lib/admin/metrics/measure/query_helper.rb @@ -15,6 +15,14 @@ module Admin::Metrics::Measure::QueryHelper ActiveRecord::Base.sanitize_sql_array(sql_array) end + def generated_series_days + Arel.sql( + <<~SQL.squish + SELECT generate_series(timestamp :start_at, :end_at, '1 day')::date AS period + SQL + ) + end + def account_domain_sql(include_subdomains) if include_subdomains "accounts.domain IN (SELECT domain FROM instances WHERE reverse('.' || domain) LIKE reverse('.' || :domain::text))" diff --git a/app/lib/admin/metrics/measure/resolved_reports_measure.rb b/app/lib/admin/metrics/measure/resolved_reports_measure.rb index 780db75a10..ecfd779c86 100644 --- a/app/lib/admin/metrics/measure/resolved_reports_measure.rb +++ b/app/lib/admin/metrics/measure/resolved_reports_measure.rb @@ -32,7 +32,7 @@ class Admin::Metrics::Measure::ResolvedReportsMeasure < Admin::Metrics::Measure: SELECT count(*) FROM resolved_reports ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) AS axis SQL end diff --git a/app/lib/admin/metrics/measure/tag_servers_measure.rb b/app/lib/admin/metrics/measure/tag_servers_measure.rb index f273d739d0..5db1076062 100644 --- a/app/lib/admin/metrics/measure/tag_servers_measure.rb +++ b/app/lib/admin/metrics/measure/tag_servers_measure.rb @@ -40,7 +40,7 @@ class Admin::Metrics::Measure::TagServersMeasure < Admin::Metrics::Measure::Base SELECT COUNT(*) FROM tag_servers ) AS value FROM ( - SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period + #{generated_series_days} ) as axis SQL end From 1622f7aeb9e911d43296caef45e17181652c9c0e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 03:48:42 -0400 Subject: [PATCH 376/658] Remove duplicate fabricator validity checks (#29667) --- spec/models/import_spec.rb | 5 ----- spec/models/poll_spec.rb | 8 -------- 2 files changed, 13 deletions(-) diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb index 3605f0b9bf..10df5f8c0b 100644 --- a/spec/models/import_spec.rb +++ b/spec/models/import_spec.rb @@ -8,11 +8,6 @@ RSpec.describe Import do let(:data) { attachment_fixture('imports.txt') } describe 'validations' do - it 'has a valid parameters' do - import = described_class.create(account: account, type: type, data: data) - expect(import).to be_valid - end - it 'is invalid without an type' do import = described_class.create(account: account, data: data) expect(import).to model_have_error_on_field(:type) diff --git a/spec/models/poll_spec.rb b/spec/models/poll_spec.rb index 5aa5548cc8..ebcc459078 100644 --- a/spec/models/poll_spec.rb +++ b/spec/models/poll_spec.rb @@ -31,14 +31,6 @@ describe Poll do end describe 'validations' do - context 'when valid' do - let(:poll) { Fabricate.build(:poll) } - - it 'is valid with valid attributes' do - expect(poll).to be_valid - end - end - context 'when not valid' do let(:poll) { Fabricate.build(:poll, expires_at: nil) } From 665f6f09a07fa9d1d813e8343f1687b369e7f3dc Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 04:50:51 -0400 Subject: [PATCH 377/658] Add expired/revoked scopes for doorkeeper models via extension modules (#29936) --- app/lib/access_grant_extension.rb | 10 ++++++++++ app/lib/access_token_extension.rb | 4 ++++ app/lib/vacuum/access_tokens_vacuum.rb | 8 ++++---- app/models/web/push_subscription.rb | 2 +- config/application.rb | 1 + 5 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 app/lib/access_grant_extension.rb diff --git a/app/lib/access_grant_extension.rb b/app/lib/access_grant_extension.rb new file mode 100644 index 0000000000..bf8f5ae25a --- /dev/null +++ b/app/lib/access_grant_extension.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module AccessGrantExtension + extend ActiveSupport::Concern + + included do + scope :expired, -> { where.not(expires_in: nil).where('created_at + MAKE_INTERVAL(secs => expires_in) < NOW()') } + scope :revoked, -> { where.not(revoked_at: nil).where(revoked_at: ...Time.now.utc) } + end +end diff --git a/app/lib/access_token_extension.rb b/app/lib/access_token_extension.rb index 4e9585dd1e..6e06f988a5 100644 --- a/app/lib/access_token_extension.rb +++ b/app/lib/access_token_extension.rb @@ -9,6 +9,10 @@ module AccessTokenExtension has_many :web_push_subscriptions, class_name: 'Web::PushSubscription', inverse_of: :access_token after_commit :push_to_streaming_api + + scope :expired, -> { where.not(expires_in: nil).where('created_at + MAKE_INTERVAL(secs => expires_in) < NOW()') } + scope :not_revoked, -> { where(revoked_at: nil) } + scope :revoked, -> { where.not(revoked_at: nil).where(revoked_at: ...Time.now.utc) } end def revoke(clock = Time) diff --git a/app/lib/vacuum/access_tokens_vacuum.rb b/app/lib/vacuum/access_tokens_vacuum.rb index a224f6d638..281ae22bf0 100644 --- a/app/lib/vacuum/access_tokens_vacuum.rb +++ b/app/lib/vacuum/access_tokens_vacuum.rb @@ -9,12 +9,12 @@ class Vacuum::AccessTokensVacuum private def vacuum_revoked_access_tokens! - Doorkeeper::AccessToken.where.not(expires_in: nil).where('created_at + make_interval(secs => expires_in) < NOW()').in_batches.delete_all - Doorkeeper::AccessToken.where.not(revoked_at: nil).where('revoked_at < NOW()').in_batches.delete_all + Doorkeeper::AccessToken.expired.in_batches.delete_all + Doorkeeper::AccessToken.revoked.in_batches.delete_all end def vacuum_revoked_access_grants! - Doorkeeper::AccessGrant.where.not(expires_in: nil).where('created_at + make_interval(secs => expires_in) < NOW()').in_batches.delete_all - Doorkeeper::AccessGrant.where.not(revoked_at: nil).where('revoked_at < NOW()').in_batches.delete_all + Doorkeeper::AccessGrant.expired.in_batches.delete_all + Doorkeeper::AccessGrant.revoked.in_batches.delete_all end end diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb index b482ad3afe..ddfd08146e 100644 --- a/app/models/web/push_subscription.rb +++ b/app/models/web/push_subscription.rb @@ -75,7 +75,7 @@ class Web::PushSubscription < ApplicationRecord class << self def unsubscribe_for(application_id, resource_owner) - access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id, revoked_at: nil).pluck(:id) + access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id).not_revoked.pluck(:id) where(access_token_id: access_token_ids).delete_all end end diff --git a/config/application.rb b/config/application.rb index b3a9b99ff5..65407da05c 100644 --- a/config/application.rb +++ b/config/application.rb @@ -115,6 +115,7 @@ module Mastodon Doorkeeper::AuthorizationsController.layout 'modal' Doorkeeper::AuthorizedApplicationsController.layout 'admin' Doorkeeper::Application.include ApplicationExtension + Doorkeeper::AccessGrant.include AccessGrantExtension Doorkeeper::AccessToken.include AccessTokenExtension Devise::FailureApp.include AbstractController::Callbacks Devise::FailureApp.include Localized From 410370eecdcc6ad7aeac30c48957d3b044e7cabe Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 05:40:47 -0400 Subject: [PATCH 378/658] Extract `PERMITTED_PARAMS` constant from `admin/domain_blocks` controller (#30380) --- .../admin/domain_blocks_controller.rb | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb index 325b33df80..16a8cb9eea 100644 --- a/app/controllers/admin/domain_blocks_controller.rb +++ b/app/controllers/admin/domain_blocks_controller.rb @@ -4,6 +4,18 @@ module Admin class DomainBlocksController < BaseController before_action :set_domain_block, only: [:destroy, :edit, :update] + PERMITTED_PARAMS = %i( + domain + obfuscate + private_comment + public_comment + reject_media + reject_reports + severity + ).freeze + + PERMITTED_UPDATE_PARAMS = PERMITTED_PARAMS.without(:domain).freeze + def batch authorize :domain_block, :create? @form = Form::DomainBlockBatch.new(form_domain_block_batch_params.merge(current_account: current_account, action: action_from_button)) @@ -88,11 +100,17 @@ module Admin end def update_params - params.require(:domain_block).permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate) + params + .require(:domain_block) + .slice(*PERMITTED_UPDATE_PARAMS) + .permit(*PERMITTED_UPDATE_PARAMS) end def resource_params - params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate) + params + .require(:domain_block) + .slice(*PERMITTED_PARAMS) + .permit(*PERMITTED_PARAMS) end def form_domain_block_batch_params From f48f39a7679667da51171a77a0e1bcbc7512cd36 Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Tue, 11 Jun 2024 14:54:37 +0200 Subject: [PATCH 379/658] Fix cutoff of instance name (#30598) --- app/javascript/styles/mastodon/forms.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index f6ec44fb53..26bb2bee14 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -613,9 +613,10 @@ code { font-family: inherit; pointer-events: none; cursor: default; - max-width: 140px; + max-width: 50%; white-space: nowrap; overflow: hidden; + text-overflow: ellipsis; &::after { content: ''; From 328d3a87f5749b5b9ea2c17289fc7a53dbaa6d7b Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 11 Jun 2024 15:58:10 +0200 Subject: [PATCH 380/658] Fix libvips color extraction when multiple maxima differ only on blue component (#30632) --- lib/paperclip/color_extractor.rb | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/paperclip/color_extractor.rb b/lib/paperclip/color_extractor.rb index 0f168d233b..378af0961d 100644 --- a/lib/paperclip/color_extractor.rb +++ b/lib/paperclip/color_extractor.rb @@ -122,26 +122,28 @@ module Paperclip colors['out_array'].zip(colors['x_array'], colors['y_array']).map do |v, x, y| rgb_from_xyv(histogram, x, y, v) - end.reverse + end.flatten.reverse.uniq end # rubocop:disable Naming/MethodParameterName def rgb_from_xyv(image, x, y, v) pixel = image.getpoint(x, y) - # Unfortunately, we only have the first 2 dimensions, so try to - # guess the third one by looking up the value + # As we only have the first 2 dimensions for this maximum, we + # can't distinguish with different maxima with the same `r` and `g` + # values but different `b` values. + # + # Therefore, we return an array of maxima, which is always non-empty, + # but may contain multiple colors with the same values. - # NOTE: this means that if multiple bins with the same `r` and `g` - # components have the same number of occurrences, we will always return - # the one with the lowest `b` value. This means that in case of a tie, - # we will return the same color twice and skip the ones it tied with. - z = pixel.find_index(v) + pixel.filter_map.with_index do |pv, z| + next if pv != v - r = (x + 0.5) * 256 / BINS - g = (y + 0.5) * 256 / BINS - b = (z + 0.5) * 256 / BINS - ColorDiff::Color::RGB.new(r, g, b) + r = (x + 0.5) * 256 / BINS + g = (y + 0.5) * 256 / BINS + b = (z + 0.5) * 256 / BINS + ColorDiff::Color::RGB.new(r, g, b) + end end def w3c_contrast(color1, color2) From b124dff1748797e54256e1c8161d18513b921458 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 15:58:40 +0200 Subject: [PATCH 381/658] chore(deps): update opentelemetry-ruby (non-major) (#30648) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 984bc32d49..c2253fe19c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -498,6 +498,10 @@ GEM opentelemetry-semantic_conventions opentelemetry-helpers-sql-obfuscation (0.1.0) opentelemetry-common (~> 0.20) + opentelemetry-instrumentation-action_mailer (0.1.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-active_support (~> 0.1) + opentelemetry-instrumentation-base (~> 0.22.1) opentelemetry-instrumentation-action_pack (0.9.0) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) @@ -551,8 +555,9 @@ GEM opentelemetry-api (~> 1.0) opentelemetry-common (~> 0.20.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-rails (0.30.1) + opentelemetry-instrumentation-rails (0.30.2) opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-action_mailer (~> 0.1.0) opentelemetry-instrumentation-action_pack (~> 0.9.0) opentelemetry-instrumentation-action_view (~> 0.7.0) opentelemetry-instrumentation-active_job (~> 0.7.0) From 62d070c438a2cccb6af486a02d8c6839d642c827 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 09:59:56 -0400 Subject: [PATCH 382/658] Check both before/after state in `AccountDomainBlock` spec (#30640) --- spec/models/account_domain_block_spec.rb | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/spec/models/account_domain_block_spec.rb b/spec/models/account_domain_block_spec.rb index 10bd579363..d994403b8e 100644 --- a/spec/models/account_domain_block_spec.rb +++ b/spec/models/account_domain_block_spec.rb @@ -3,22 +3,30 @@ require 'rails_helper' RSpec.describe AccountDomainBlock do + let(:account) { Fabricate(:account) } + it 'removes blocking cache after creation' do - account = Fabricate(:account) Rails.cache.write("exclude_domains_for:#{account.id}", 'a.domain.already.blocked') - described_class.create!(account: account, domain: 'a.domain.blocked.later') - - expect(Rails.cache.exist?("exclude_domains_for:#{account.id}")).to be false + expect { block_domain_for_account('a.domain.blocked.later') } + .to change { account_has_exclude_domains_cache? }.to(false) end it 'removes blocking cache after destruction' do - account = Fabricate(:account) - block = described_class.create!(account: account, domain: 'domain') + block = block_domain_for_account('domain') Rails.cache.write("exclude_domains_for:#{account.id}", 'domain') - block.destroy! + expect { block.destroy! } + .to change { account_has_exclude_domains_cache? }.to(false) + end - expect(Rails.cache.exist?("exclude_domains_for:#{account.id}")).to be false + private + + def block_domain_for_account(domain) + Fabricate(:account_domain_block, account: account, domain: domain) + end + + def account_has_exclude_domains_cache? + Rails.cache.exist?("exclude_domains_for:#{account.id}") end end From 978601a0ae556c4e214df8f6d73181c2a6359531 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 11:29:41 -0400 Subject: [PATCH 383/658] Extract permitted params constant in v1/admin/tags (#30652) --- app/controllers/api/v1/admin/tags_controller.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/admin/tags_controller.rb b/app/controllers/api/v1/admin/tags_controller.rb index 67d987d0e3..283383acb4 100644 --- a/app/controllers/api/v1/admin/tags_controller.rb +++ b/app/controllers/api/v1/admin/tags_controller.rb @@ -13,6 +13,13 @@ class Api::V1::Admin::TagsController < Api::BaseController LIMIT = 100 + PERMITTED_PARAMS = %i( + display_name + listable + trendable + usable + ).freeze + def index authorize :tag, :index? render json: @tags, each_serializer: REST::Admin::TagSerializer @@ -40,7 +47,9 @@ class Api::V1::Admin::TagsController < Api::BaseController end def tag_params - params.permit(:display_name, :trendable, :usable, :listable) + params + .slice(*PERMITTED_PARAMS) + .permit(*PERMITTED_PARAMS) end def next_path From 921b0db5440cc6e0bc990d6f0186c43aaa887fe9 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 11 Jun 2024 17:29:45 +0200 Subject: [PATCH 384/658] Add `noindex` meta tag and `rel=canonical` link to redirect interstitials (#30651) --- app/views/redirects/show.html.haml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/redirects/show.html.haml b/app/views/redirects/show.html.haml index 0d09387a9c..64436e05d1 100644 --- a/app/views/redirects/show.html.haml +++ b/app/views/redirects/show.html.haml @@ -1,3 +1,7 @@ +- content_for :header_tags do + %meta{ name: 'robots', content: 'noindex, noarchive' }/ + %link{ rel: 'canonical', href: @redirect_path } + .redirect .redirect__logo = link_to render_logo, root_path From d818ddd6870094e89e58ef61f37da4cb73935856 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 11:36:21 -0400 Subject: [PATCH 385/658] Extract `SIGN_COUNT_LIMIT` constant in `WebauthnCredential` class (#30636) --- app/models/webauthn_credential.rb | 4 +++- ...bauthn_credentials_spec.rb => webauthn_credential_spec.rb} | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) rename spec/models/{webauthn_credentials_spec.rb => webauthn_credential_spec.rb} (95%) diff --git a/app/models/webauthn_credential.rb b/app/models/webauthn_credential.rb index 4fa31ece52..d7ed1b9d40 100644 --- a/app/models/webauthn_credential.rb +++ b/app/models/webauthn_credential.rb @@ -15,9 +15,11 @@ # class WebauthnCredential < ApplicationRecord + SIGN_COUNT_LIMIT = (2**63) + validates :external_id, :public_key, :nickname, :sign_count, presence: true validates :external_id, uniqueness: true validates :nickname, uniqueness: { scope: :user_id } validates :sign_count, - numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: (2**63) - 1 } + numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: SIGN_COUNT_LIMIT - 1 } end diff --git a/spec/models/webauthn_credentials_spec.rb b/spec/models/webauthn_credential_spec.rb similarity index 95% rename from spec/models/webauthn_credentials_spec.rb rename to spec/models/webauthn_credential_spec.rb index 9631245e11..23f0229a67 100644 --- a/spec/models/webauthn_credentials_spec.rb +++ b/spec/models/webauthn_credential_spec.rb @@ -71,8 +71,8 @@ RSpec.describe WebauthnCredential do expect(webauthn_credential).to model_have_error_on_field(:sign_count) end - it 'is invalid if sign_count is greater 2**63 - 1' do - webauthn_credential = Fabricate.build(:webauthn_credential, sign_count: 2**63) + it 'is invalid if sign_count is greater than the limit' do + webauthn_credential = Fabricate.build(:webauthn_credential, sign_count: (described_class::SIGN_COUNT_LIMIT * 2)) webauthn_credential.valid? From f214813919309b0b8bda628835029e204d56dd31 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 11 Jun 2024 19:54:27 +0200 Subject: [PATCH 386/658] Adapt settings spec to glitch-soc --- .../settings/preferences/appearance_controller_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/controllers/settings/preferences/appearance_controller_spec.rb b/spec/controllers/settings/preferences/appearance_controller_spec.rb index 84b8277250..c59d315104 100644 --- a/spec/controllers/settings/preferences/appearance_controller_spec.rb +++ b/spec/controllers/settings/preferences/appearance_controller_spec.rb @@ -23,11 +23,11 @@ describe Settings::Preferences::AppearanceController do end describe 'PUT #update' do - subject { put :update, params: { user: { settings_attributes: { theme: 'contrast' } } } } + subject { put :update, params: { user: { settings_attributes: { skin: 'contrast' } } } } it 'redirects correctly' do expect { subject } - .to change { user.reload.settings.theme }.to('contrast') + .to change { user.reload.settings.skin }.to('contrast') expect(response).to redirect_to(settings_preferences_appearance_path) end From cec8e34b250c368ec6c4a5acb75eed311aa901bf Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 11 Jun 2024 16:29:00 -0400 Subject: [PATCH 387/658] Remove unused CI env vars (#30660) --- .github/workflows/test-migrations-one-step.yml | 1 - .github/workflows/test-migrations-two-step.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/test-migrations-one-step.yml b/.github/workflows/test-migrations-one-step.yml index 1ff5cc06b9..104e1b067c 100644 --- a/.github/workflows/test-migrations-one-step.yml +++ b/.github/workflows/test-migrations-one-step.yml @@ -57,7 +57,6 @@ jobs: - 6379:6379 env: - CONTINUOUS_INTEGRATION: true DB_HOST: localhost DB_USER: postgres DB_PASS: postgres diff --git a/.github/workflows/test-migrations-two-step.yml b/.github/workflows/test-migrations-two-step.yml index 6698847315..c4209d6329 100644 --- a/.github/workflows/test-migrations-two-step.yml +++ b/.github/workflows/test-migrations-two-step.yml @@ -57,7 +57,6 @@ jobs: - 6379:6379 env: - CONTINUOUS_INTEGRATION: true DB_HOST: localhost DB_USER: postgres DB_PASS: postgres From 1dfd51628416598d2386621b6229a4f169cd360e Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 12 Jun 2024 09:28:28 +0200 Subject: [PATCH 388/658] Fix duplicate `@context` attribute in user export (#30653) --- app/services/backup_service.rb | 4 ++-- spec/services/backup_service_spec.rb | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/services/backup_service.rb b/app/services/backup_service.rb index 886bab1ebf..1e90184376 100644 --- a/app/services/backup_service.rb +++ b/app/services/backup_service.rb @@ -19,8 +19,8 @@ class BackupService < BaseService def build_outbox_json!(file) skeleton = serialize(collection_presenter, ActivityPub::CollectionSerializer) - skeleton[:@context] = full_context - skeleton[:orderedItems] = ['!PLACEHOLDER!'] + skeleton['@context'] = full_context + skeleton['orderedItems'] = ['!PLACEHOLDER!'] skeleton = Oj.dump(skeleton) prepend, append = skeleton.split('"!PLACEHOLDER!"') add_comma = false diff --git a/spec/services/backup_service_spec.rb b/spec/services/backup_service_spec.rb index b4cb60083b..145b06e372 100644 --- a/spec/services/backup_service_spec.rb +++ b/spec/services/backup_service_spec.rb @@ -55,9 +55,11 @@ RSpec.describe BackupService do end def expect_outbox_export - json = export_json(:outbox) + body = export_json_raw(:outbox) + json = Oj.load(body) aggregate_failures do + expect(body.scan('@context').count).to eq 1 expect(json['@context']).to_not be_nil expect(json['type']).to eq 'OrderedCollection' expect(json['totalItems']).to eq 2 @@ -85,8 +87,12 @@ RSpec.describe BackupService do end end + def export_json_raw(type) + read_zip_file(backup, "#{type}.json") + end + def export_json(type) - Oj.load(read_zip_file(backup, "#{type}.json")) + Oj.load(export_json_raw(type)) end def include_create_item(status) From ced463360e39b92689144e366b6f3a9ceabf1bf7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:48:31 +0200 Subject: [PATCH 389/658] New Crowdin Translations (automated) (#30666) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/be.json | 19 ++++++++++++++++++- app/javascript/mastodon/locales/ur.json | 5 +++++ config/locales/be.yml | 3 +++ config/locales/doorkeeper.be.yml | 2 ++ config/locales/doorkeeper.fy.yml | 2 ++ config/locales/fy.yml | 1 + config/locales/simple_form.be.yml | 6 ++++++ config/locales/simple_form.fy.yml | 2 ++ 8 files changed, 39 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 61e96e4b58..041d90775b 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -308,6 +308,8 @@ "follow_requests.unlocked_explanation": "Ваш акаўнт не схаваны, аднак прадстаўнікі {domain} палічылі, што вы можаце захацець праглядзець запыты на падпіску з гэтых профіляў уручную.", "follow_suggestions.curated_suggestion": "Выбар адміністрацыі", "follow_suggestions.dismiss": "Не паказваць зноў", + "follow_suggestions.featured_longer": "Адабраныя камандай {domain} уручную", + "follow_suggestions.friends_of_friends_longer": "Папулярнае сярод людзей, на якіх Вы падпісаны", "follow_suggestions.hints.featured": "Гэты профіль быў выбраны ўручную камандай {domain}.", "follow_suggestions.hints.friends_of_friends": "Гэты профіль папулярны сярод людзей, на якіх вы падпісаліся.", "follow_suggestions.hints.most_followed": "Гэты профіль - адзін з профіляў з самай вялікай колькасцю падпісак на {domain}.", @@ -315,6 +317,8 @@ "follow_suggestions.hints.similar_to_recently_followed": "Гэты профіль падобны на профілі, на якія вы нядаўна падпісаліся.", "follow_suggestions.personalized_suggestion": "Персаналізаваная прапанова", "follow_suggestions.popular_suggestion": "Папулярная прапанова", + "follow_suggestions.popular_suggestion_longer": "Папулярнае на {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Падобныя профілі, за якімі вы нядаўна сачылі", "follow_suggestions.view_all": "Праглядзець усё", "follow_suggestions.who_to_follow": "На каго падпісацца", "followed_tags": "Падпіскі", @@ -410,6 +414,7 @@ "limited_account_hint.action": "Усе роўна паказваць профіль", "limited_account_hint.title": "Гэты профіль быў схаваны мадэратарамі", "link_preview.author": "Ад {name}", + "link_preview.more_from_author": "Больш ад {name}", "lists.account.add": "Дадаць да спісу", "lists.account.remove": "Выдаліць са спісу", "lists.delete": "Выдаліць спіс", @@ -458,7 +463,7 @@ "navigation_bar.opened_in_classic_interface": "Допісы, уліковыя запісы і іншыя спецыфічныя старонкі па змоўчанні адчыняюцца ў класічным вэб-інтэрфейсе.", "navigation_bar.personal": "Асабістае", "navigation_bar.pins": "Замацаваныя допісы", - "navigation_bar.preferences": "Параметры", + "navigation_bar.preferences": "Налады", "navigation_bar.public_timeline": "Глабальная стужка", "navigation_bar.search": "Пошук", "navigation_bar.security": "Бяспека", @@ -470,10 +475,22 @@ "notification.follow_request": "{name} адправіў запыт на падпіску", "notification.mention": "{name} згадаў вас", "notification.moderation-warning.learn_more": "Даведацца больш", + "notification.moderation_warning": "Вы атрымалі папярэджанне аб мадэрацыі", + "notification.moderation_warning.action_delete_statuses": "Некаторыя вашыя допісы былі выдаленыя.", + "notification.moderation_warning.action_disable": "Ваш уліковы запіс быў адключаны.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "Некаторыя з вашых допісаў былі пазначаныя як далікатныя.", + "notification.moderation_warning.action_none": "Ваш уліковы запіс атрымаў папярэджанне ад мадэратараў.", + "notification.moderation_warning.action_sensitive": "З гэтага моманту вашыя допісы будуць пазначаныя як далікатныя.", + "notification.moderation_warning.action_silence": "Ваш уліковы запіс быў абмежаваны.", + "notification.moderation_warning.action_suspend": "Ваш уліковы запіс быў прыпынены.", "notification.own_poll": "Ваша апытанне скончылася", "notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася", "notification.reblog": "{name} пашырыў ваш допіс", + "notification.relationships_severance_event": "Страціў сувязь з {name}", + "notification.relationships_severance_event.account_suspension": "Адміністратар з {from} прыпыніў працу {target}, што азначае, што вы больш не можаце атрымліваць ад іх абнаўлення ці ўзаемадзейнічаць з імі.", + "notification.relationships_severance_event.domain_block": "Адміністратар з {from} заблакіраваў {target}, у тым ліку {followersCount} вашых падпісчыка(-аў) і {followingCount, plural, one {# уліковы запіс} few {# уліковыя запісы} many {# уліковых запісаў} other {# уліковых запісаў}}.", "notification.relationships_severance_event.learn_more": "Даведацца больш", + "notification.relationships_severance_event.user_domain_block": "Вы заблакіравалі {target} выдаліўшы {followersCount} сваіх падпісчыкаў і {followingCount, plural, one {# уліковы запіс} few {# уліковыя запісы} many {# уліковых запісаў} other {# уліковых запісаў}}, за якімі вы сочыце.", "notification.status": "Новы допіс ад {name}", "notification.update": "Допіс {name} адрэдагаваны", "notification_requests.accept": "Прыняць", diff --git a/app/javascript/mastodon/locales/ur.json b/app/javascript/mastodon/locales/ur.json index 37f156c28f..6f3debae2e 100644 --- a/app/javascript/mastodon/locales/ur.json +++ b/app/javascript/mastodon/locales/ur.json @@ -26,6 +26,7 @@ "account.featured_tags.last_status_never": "کوئی مراسلہ نہیں", "account.featured_tags.title": "{name} کے نمایاں ہیش ٹیگز", "account.follow": "پیروی کریں", + "account.follow_back": "اکاؤنٹ کو فالو بیک ", "account.followers": "پیروکار", "account.followers.empty": "\"ہنوز اس صارف کی کوئی پیروی نہیں کرتا\".", "account.followers_counter": "{count, plural,one {{counter} پیروکار} other {{counter} پیروکار}}", @@ -46,6 +47,7 @@ "account.mute_notifications_short": "نوٹیفیکیشنز کو خاموش کریں", "account.mute_short": "خاموش", "account.muted": "خاموش کردہ", + "account.mutual": "میوچول اکاؤنٹ", "account.no_bio": "کوئی تفصیل نہیں دی گئی۔", "account.open_original_page": "اصل صفحہ کھولیں", "account.posts": "ٹوٹ", @@ -65,7 +67,10 @@ "account.unmute_notifications_short": "نوٹیفیکیشنز کو خاموش نہ کریں", "account.unmute_short": "کو خاموش نہ کریں", "account_note.placeholder": "Click to add a note", + "admin.dashboard.daily_retention": "ایڈمن ڈیش بورڈ کو ڈیلی چیک ان کریں", + "admin.dashboard.monthly_retention": "ایڈمن کیش بورڈ کو منتھلی چیک ان کریں", "admin.dashboard.retention.average": "اوسط", + "admin.dashboard.retention.cohort": "Sign-up month", "admin.dashboard.retention.cohort_size": "نئے یسرز", "alert.rate_limited.message": "\"{retry_time, time, medium} کے بعد کوشش کریں\".", "alert.rate_limited.title": "محدود شرح", diff --git a/config/locales/be.yml b/config/locales/be.yml index 6f1f189523..a14ba3d224 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -291,6 +291,7 @@ be: update_custom_emoji_html: "%{name} абнавіў эмодзі %{target}" update_domain_block_html: "%{name} абнавіў блакіроўку дамена для %{target}" update_ip_block_html: "%{name} змяніў правіла для IP %{target}" + update_report_html: "%{name} абнавіў скаргу %{target}" update_status_html: "%{name} абнавіў допіс %{target}" update_user_role_html: "%{name} змяніў ролю %{target}" deleted_account: выдалены ўліковы запіс @@ -779,6 +780,7 @@ be: desc_html: Гэта функцыянальнасць залежыць ад знешніх скрыптоў hCaptcha, што можа быць праблемай бяспекі і прыватнасці. Акрамя таго, гэта можа зрабіць працэс рэгістрацыі значна менш даступным для некаторых людзей, асабліва інвалідаў. Па гэтых прычынах, калі ласка, разгледзьце альтэрнатыўныя меры, такія як рэгістрацыя на аснове зацвярджэння або запрашэння. title: Патрабаваць ад новых карыстальнікаў рашэння CAPTCHA для пацверджання іх уліковага запісу content_retention: + danger_zone: Небяспечная зона preamble: Кантралюйце, як створаны карыстальнікамі кантэнт захоўваецца ў Mastodon. title: Утрыманне кантэнту default_noindex: @@ -983,6 +985,7 @@ be: delete: Выдаліць edit_preset: Рэдагаваць шаблон папярэджання empty: Вы яшчэ не вызначылі ніякіх шаблонаў папярэджанняў. + title: Папярэджальныя прадусталёўкі webhooks: add_new: Дадаць канцавую кропку delete: Выдаліць diff --git a/config/locales/doorkeeper.be.yml b/config/locales/doorkeeper.be.yml index 748cbeafa1..f4faed1f09 100644 --- a/config/locales/doorkeeper.be.yml +++ b/config/locales/doorkeeper.be.yml @@ -135,6 +135,7 @@ be: media: Мультымедыйныя далучэнні mutes: Ігнараваныя notifications: Апавяшчэнні + profile: Ваш профіль Mastodon push: Push-апавяшчэнні reports: Скаргі search: Пошук @@ -165,6 +166,7 @@ be: admin:write:reports: мадэраваць скаргі crypto: выкарыстоўваць скразное шыфраванне (end-to-end) follow: змяняць зносіны ўліковага запісу + profile: чытаць толькі інфармацыю профілю вашага ўліковага запісу push: атрымліваць push-апавяшчэнні read: чытаць усе даныя вашага ўліковага запісу read:accounts: бачыць інфармацыю аб уліковых запісах diff --git a/config/locales/doorkeeper.fy.yml b/config/locales/doorkeeper.fy.yml index a43defc427..1cf2d32212 100644 --- a/config/locales/doorkeeper.fy.yml +++ b/config/locales/doorkeeper.fy.yml @@ -135,6 +135,7 @@ fy: media: Mediabylagen mutes: Negearre notifications: Meldingen + profile: Jo Mastodon-profyl push: Pushmeldingen reports: Rapportaazjes search: Sykje @@ -165,6 +166,7 @@ fy: admin:write:reports: moderaasjemaatregelen nimme yn rapportaazjes crypto: ein-ta-ein-fersifering brûke follow: relaasjes tusken accounts bewurkje + profile: allinnich de profylgegevens fan jo account lêze push: jo pushmeldingen ûntfange read: alle gegevens fan jo account lêze read:accounts: accountynformaasje besjen diff --git a/config/locales/fy.yml b/config/locales/fy.yml index c8e287732a..54e28608ef 100644 --- a/config/locales/fy.yml +++ b/config/locales/fy.yml @@ -285,6 +285,7 @@ fy: update_custom_emoji_html: Emoji %{target} is troch %{name} bywurke update_domain_block_html: "%{name} hat de domeinblokkade bywurke foar %{target}" update_ip_block_html: "%{name} hat de rigel foar IP %{target} wizige" + update_report_html: Rapportaazje %{target} is troch %{name} bywurke update_status_html: "%{name} hat de berjochten %{target} bywurke" update_user_role_html: "%{name} hat de rol %{target} wizige" deleted_account: fuortsmiten account diff --git a/config/locales/simple_form.be.yml b/config/locales/simple_form.be.yml index f8000a1c81..101d40f117 100644 --- a/config/locales/simple_form.be.yml +++ b/config/locales/simple_form.be.yml @@ -77,10 +77,15 @@ be: warn: Схаваць адфільтраваны кантэнт за папярэджаннем з назвай фільтру form_admin_settings: activity_api_enabled: Падлік лакальна апублікаваных пастоў, актыўных карыстальнікаў і новых рэгістрацый у тыдзень + app_icon: WEBP, PNG, GIF ці JPG. Заменіце прадвызначаны значок праграмы на мабільных прыладах карыстальніцкім значком. + backups_retention_period: Карыстальнікі могуць ствараць архівы сваіх допісаў для наступнай запампоўкі. Пры станоўчай колькасці дзён гэтыя архівы будуць аўтаматычна выдаляцца са сховішча пасля заканчэння названай колькасці дзён. bootstrap_timeline_accounts: Гэтыя ўліковыя запісы будуць замацаваны ў топе рэкамендацый для новых карыстальнікаў. closed_registrations_message: Паказваецца, калі рэгістрацыя закрытая + content_cache_retention_period: Усе допісы з іншых сервераў (уключаючы пашырэнні і адказы) будуць выдаленыя праз паказаную колькасць дзён, незалежна ад таго, як лакальны карыстальнік узаемадзейнічаў з гэтымі допісамі. Гэта датычыцца і тых допісаў, якія лакальны карыстальнік пазначыў у закладкі або ўпадабанае. Прыватныя згадкі паміж карыстальнікамі з розных інстанс таксама будуць страчаныя і не змогуць быць адноўлены. Выкарыстанне гэтай налады прызначана для асобнікаў спецыяльнага прызначэння і парушае многія чаканні карыстальнікаў пры выкарыстанні ў агульных мэтах. custom_css: Вы можаце прымяняць карыстальніцкія стылі ў вэб-версіі Mastodon. + favicon: WEBP, PNG, GIF ці JPG. Замяняе прадвызначаны favicon Mastodon на ўласны значок. mascot: Замяняе ілюстрацыю ў пашыраным вэб-інтэрфейсе. + media_cache_retention_period: Медыяфайлы з допісаў, зробленых выдаленымі карыстальнікамі, кэшыруюцца на вашым серверы. Пры станоўчым значэнні медыяфайлы будуць выдалены праз пазначаную колькасць дзён. Калі медыядадзеныя будуць запытаны пасля выдалення, яны будуць загружаны паўторна, калі зыходны кантэнт усё яшчэ даступны. У сувязі з абмежаваннямі на частату абнаўлення відарысаў іншых сайтаў, рэкамендуецца ўсталяваць значэнне не менш за 14 дзён, інакш відарысы не будуць загружацца па запыце раней за гэты тэрмін. peers_api_enabled: Спіс даменных імён, з якімі сутыкнуўся гэты сервер у федэсвеце. Дадзеныя аб тым, ці знаходзіцеся вы з пэўным серверам у федэрацыі, не ўключаныя, ёсць толькі тое, што ваш сервер ведае пра гэта. Гэта выкарыстоўваецца сэрвісамі, якія збіраюць статыстыку па федэрацыі ў агульным сэнсе. profile_directory: Дырэкторыя профіляў змяшчае спіс усіх карыстальнікаў, якія вырашылі быць бачнымі. require_invite_text: Калі рэгістрацыя патрабуе ручнога пацвержання, зрабіце поле "Чаму вы хочаце далучыцца?" абавязковым @@ -240,6 +245,7 @@ be: backups_retention_period: Працягласць захавання архіву карыстальніка bootstrap_timeline_accounts: Заўсёды раіць гэтыя ўліковыя запісы новым карыстальнікам closed_registrations_message: Уласнае паведамленне, калі рэгістрацыя немагчымая + content_cache_retention_period: Перыяд захоўвання выдаленага змесціва custom_css: CSS карыстальніка mascot: Уласны маскот(спадчына) media_cache_retention_period: Працягласць захавання кэшу для медыя diff --git a/config/locales/simple_form.fy.yml b/config/locales/simple_form.fy.yml index 8d599324b3..9e0f67b707 100644 --- a/config/locales/simple_form.fy.yml +++ b/config/locales/simple_form.fy.yml @@ -77,11 +77,13 @@ fy: warn: Ferstopje de filtere ynhâld efter in warskôging, mei de titel fan it filter as warskôgingstekst form_admin_settings: activity_api_enabled: Tal lokaal publisearre artikelen, aktive brûkers en nije registraasjes yn wyklikse werjefte + app_icon: WEBP, PNG, GIF of JPG. Ferfangt op mobile apparaten it standert app-pictogram mei in oanpast piktogram. backups_retention_period: Brûkers hawwe de mooglikheid om argiven fan harren berjochten te generearjen om letter te downloaden. Wannear ynsteld op in positive wearde, wurde dizze argiven automatysk fuortsmiten út jo ûnthâld nei it opjûne oantal dagen. bootstrap_timeline_accounts: Dizze accounts wurde boppe oan de oanrekommandaasjes oan nije brûkers toand. Meardere brûkersnammen troch komma’s skiede. closed_registrations_message: Werjûn wannear’t registraasje fan nije accounts útskeakele is content_cache_retention_period: Alle berjochten fan oare servers (ynklusyf boosts en reaksjes) wurde fuortsmiten nei it opjûne oantal dagen, nettsjinsteande iennige lokale brûkersynteraksje mei dy berjochten. Dit oanbelanget ek berjochten dy’t in lokale brûker oan harren blêdwizers tafoege hat of as favoryt markearre hat. Priveeberjochten tusken brûkers fan ferskate servers gean ek ferlern en binne ûnmooglik te werstellen. It gebrûk fan dizze ynstelling is bedoeld foar servers dy’t in spesjaal doel tsjinje en oertrêdet in protte brûkersferwachtingen wannear’t dizze foar algemien gebrûk ymplemintearre wurdt. custom_css: Jo kinne oanpaste CSS tapasse op de webferzje fan dizze Mastodon-server. + favicon: WEBP, PNG, GIF of JPG. Ferfangt de standert Mastodon-favicon mei in oanpast piktogram. mascot: Oerskriuwt de yllustraasje yn de avansearre webomjouwing. media_cache_retention_period: Mediabestannen fan berjochten fan eksterne brûkers wurde op jo server yn de buffer bewarre. Wannear ynsteld op in positive wearde, wurde media fuortsmiten nei it opjûne oantal dagen. As de mediagegevens opfrege wurde neidat se fuortsmiten binne, wurde se opnij download wannear de orizjinele ynhâld noch hieltyd beskikber is. Fanwegen beheiningen op hoe faak keppelingsfoarbylden websites fan tredden rieplachtsje, wurdt oanrekommandearre om dizze wearde yn te stellen op op syn minste 14 dagen. Oars wurde keppelingsfoarbylden net op oanfraach bywurke. peers_api_enabled: In list mei domeinnammen, dêr’t dizze server yn fediverse kontakt hân mei hat. Hjir wurdt gjin data dield, oft jo mei in bepaalde server federearrest, mar alinnich, dat jo server dat wit. Dit wurdt foar tsjinsten brûkt, dy’t statistiken oer federaasje yn algemiene sin sammelet. From dff48ff705b8193702cdef149f8cd8748365d48f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:04:54 +0200 Subject: [PATCH 390/658] fix(deps): update dependency sass to v1.77.5 (#30665) 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 33cd7b481d..b88cfaab14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15355,15 +15355,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.77.4 - resolution: "sass@npm:1.77.4" + version: 1.77.5 + resolution: "sass@npm:1.77.5" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/b9cb4882bded282aabe38d011adfce375e1f282184fcf93dc3da5d5be834c6aa53c474c15634c351ef7bd85146cfd1cc81343654cc3bcf000d78e856da4225ef + checksum: 10c0/9da049b0a3fadab419084d6becdf471e107cf6e3c8ac87cabea2feb845afac75e86c99e06ee721a5aa4f6a2d833ec5380137c4e540ab2f760edf1e4eb6139e69 languageName: node linkType: hard From 9321a454de78dc57d4382f6f366f282a111d2b31 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Jun 2024 07:38:20 -0400 Subject: [PATCH 391/658] Combine CI migration tests (#30661) --- .../workflows/test-migrations-two-step.yml | 94 ------------------- ...tions-one-step.yml => test-migrations.yml} | 32 ++++--- 2 files changed, 19 insertions(+), 107 deletions(-) delete mode 100644 .github/workflows/test-migrations-two-step.yml rename .github/workflows/{test-migrations-one-step.yml => test-migrations.yml} (66%) diff --git a/.github/workflows/test-migrations-two-step.yml b/.github/workflows/test-migrations-two-step.yml deleted file mode 100644 index c4209d6329..0000000000 --- a/.github/workflows/test-migrations-two-step.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Test two step migrations -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - pull_request: - -jobs: - pre_job: - runs-on: ubuntu-latest - - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-two-step.yml", "lib/tasks/tests.rake"]' - - test: - runs-on: ubuntu-latest - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' - - strategy: - fail-fast: false - - matrix: - postgres: - - 14-alpine - - 15-alpine - - services: - postgres: - image: postgres:${{ matrix.postgres}} - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 - - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - DISABLE_SIMPLECOV: true - RAILS_ENV: test - BUNDLE_CLEAN: true - BUNDLE_FROZEN: true - BUNDLE_WITHOUT: 'development production' - BUNDLE_JOBS: 3 - BUNDLE_RETRY: 3 - - steps: - - uses: actions/checkout@v4 - - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby - - - name: Create database - run: './bin/rails db:create' - - - name: Run historical migrations with data population - run: './bin/rails tests:migrations:prepare_database' - env: - SKIP_POST_DEPLOYMENT_MIGRATIONS: true - - - name: Run all remaining pre-deployment migrations - run: './bin/rails db:migrate' - env: - SKIP_POST_DEPLOYMENT_MIGRATIONS: true - - - name: Run all post-deployment migrations - run: './bin/rails db:migrate' - - - name: Check migration result - run: './bin/rails tests:migrations:check_database' diff --git a/.github/workflows/test-migrations-one-step.yml b/.github/workflows/test-migrations.yml similarity index 66% rename from .github/workflows/test-migrations-one-step.yml rename to .github/workflows/test-migrations.yml index 104e1b067c..f057efc11a 100644 --- a/.github/workflows/test-migrations-one-step.yml +++ b/.github/workflows/test-migrations.yml @@ -1,4 +1,5 @@ -name: Test one step migrations +name: Historical data migration test + on: push: branches-ignore: @@ -17,7 +18,7 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-one-step.yml", "lib/tasks/tests.rake"]' + paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations.yml", "lib/tasks/tests.rake"]' test: runs-on: ubuntu-latest @@ -64,7 +65,7 @@ jobs: RAILS_ENV: test BUNDLE_CLEAN: true BUNDLE_FROZEN: true - BUNDLE_WITHOUT: 'development production' + BUNDLE_WITHOUT: 'development:production' BUNDLE_JOBS: 3 BUNDLE_RETRY: 3 @@ -74,14 +75,19 @@ jobs: - name: Set up Ruby environment uses: ./.github/actions/setup-ruby - - name: Create database - run: './bin/rails db:create' + - name: Test "one step migration" flow + run: | + bin/rails db:drop + bin/rails db:create + bin/rails tests:migrations:prepare_database + bin/rails db:migrate + bin/rails tests:migrations:check_database - - name: Run historical migrations with data population - run: './bin/rails tests:migrations:prepare_database' - - - name: Run all remaining migrations - run: './bin/rails db:migrate' - - - name: Check migration result - run: './bin/rails tests:migrations:check_database' + - name: Test "two step migration" flow + run: | + bin/rails db:drop + bin/rails db:create + SKIP_POST_DEPLOYMENT_MIGRATIONS=true bin/rails tests:migrations:prepare_database + SKIP_POST_DEPLOYMENT_MIGRATIONS=true bin/rails db:migrate + bin/rails db:migrate + bin/rails tests:migrations:check_database From 47f97e113a1047c067948f385b5179fa0489180f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Jun 2024 07:39:16 -0400 Subject: [PATCH 392/658] Update the bundler-audit vulnerability DB when running (#30658) --- .github/workflows/bundler-audit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bundler-audit.yml b/.github/workflows/bundler-audit.yml index bbc31598c7..923abcd91c 100644 --- a/.github/workflows/bundler-audit.yml +++ b/.github/workflows/bundler-audit.yml @@ -31,4 +31,4 @@ jobs: uses: ./.github/actions/setup-ruby - name: Run bundler-audit - run: bundle exec bundler-audit + run: bundle exec bundler-audit check --update From 0a7249c7c687775c7ab6ef495b259cedff5f25ca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 14:41:14 +0200 Subject: [PATCH 393/658] fix(deps): update dependency pino to v9.2.0 (#30659) 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 b88cfaab14..b34f45aac0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13093,8 +13093,8 @@ __metadata: linkType: hard "pino@npm:^9.0.0": - version: 9.1.0 - resolution: "pino@npm:9.1.0" + version: 9.2.0 + resolution: "pino@npm:9.2.0" dependencies: atomic-sleep: "npm:^1.0.0" fast-redact: "npm:^3.1.1" @@ -13109,7 +13109,7 @@ __metadata: thread-stream: "npm:^3.0.0" bin: pino: bin.js - checksum: 10c0/d060530ae2e4e8f21d04bb0f44f009f94d207d7f4337f508f618416514214ddaf1b29f8c5c265153a19ce3b6480b451461f40020f916ace9d53a5aa07624b79c + checksum: 10c0/5fbd226ff7dab0961232b5aa5eca0530cdc5bb29f6bf17d929e42239293b1a587a26cc311db6abc1090c9dd57e8f7b031eae341b41d00d4a642b4f1736474c80 languageName: node linkType: hard From 54ab70dfcf39e13c055b99a4fc4aea721781af32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 14:42:04 +0200 Subject: [PATCH 394/658] chore(deps): update yarn to v4.3.0 (#30644) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- streaming/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f84d45c32e..d52f0ea1cc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/mastodon", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.2.2", + "packageManager": "yarn@4.3.0", "engines": { "node": ">=18" }, diff --git a/streaming/package.json b/streaming/package.json index 2e515167c7..ba024fe7af 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/streaming", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.2.2", + "packageManager": "yarn@4.3.0", "engines": { "node": ">=18" }, From 19f1c081e161bf8ca3325f48f7fe0194827de56a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 12 Jun 2024 08:59:32 -0400 Subject: [PATCH 395/658] Update `rubocop-rspec` to version 3.0.1 (#30655) --- .rubocop.yml | 5 ----- Gemfile | 1 + Gemfile.lock | 19 ++++++++----------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index cbc0afd281..090b89b255 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -133,11 +133,6 @@ Rails/NegateInclude: 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: - Enabled: false - # Reason: # https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnamedsubject RSpec/NamedSubject: diff --git a/Gemfile b/Gemfile index be02a65626..b00eaecbcf 100644 --- a/Gemfile +++ b/Gemfile @@ -171,6 +171,7 @@ group :development do gem 'rubocop-performance', require: false gem 'rubocop-rails', require: false gem 'rubocop-rspec', require: false + gem 'rubocop-rspec_rails', require: false # Annotates modules with schema gem 'annotate', '~> 3.2' diff --git a/Gemfile.lock b/Gemfile.lock index c2253fe19c..902ddd5f59 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -698,8 +698,8 @@ GEM responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.2.8) - strscan (>= 3.0.9) + rexml (3.3.0) + strscan rotp (6.3.0) rouge (4.2.1) rpam2 (4.0.2) @@ -746,8 +746,6 @@ GEM parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) - rubocop-factory_bot (2.25.1) - rubocop (~> 1.41) rubocop-performance (1.21.0) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) @@ -756,13 +754,11 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (2.31.0) - rubocop (~> 1.40) - rubocop-capybara (~> 2.17) - rubocop-factory_bot (~> 2.22) - rubocop-rspec_rails (~> 2.28) - rubocop-rspec_rails (2.28.3) - rubocop (~> 1.40) + rubocop-rspec (3.0.1) + rubocop (~> 1.61) + rubocop-rspec_rails (2.30.0) + rubocop (~> 1.61) + rubocop-rspec (~> 3, >= 3.0.1) ruby-prof (1.7.0) ruby-progressbar (1.13.0) ruby-saml (1.16.0) @@ -1028,6 +1024,7 @@ DEPENDENCIES rubocop-performance rubocop-rails rubocop-rspec + rubocop-rspec_rails ruby-prof ruby-progressbar (~> 1.13) ruby-vips (~> 2.2) From 99842434677ef3a01f5c7700d3b67ba5e72cd1a1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 12 Jun 2024 15:10:51 +0200 Subject: [PATCH 396/658] Fix a few visual glitches with link previews in web UI (#30670) --- app/javascript/styles/mastodon/components.scss | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 4f36d85aa9..2400f319db 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1411,10 +1411,15 @@ body > [data-popper-placement] { .audio-player, .attachment-list, .picture-in-picture-placeholder, + .more-from-author, .status-card, .hashtag-bar { margin-inline-start: $thread-margin; - width: calc(100% - ($thread-margin)); + width: calc(100% - $thread-margin); + } + + .more-from-author { + width: calc(100% - $thread-margin + 2px); } .status__content__read-more-button { @@ -4129,6 +4134,13 @@ a.status-card { border-end-start-radius: 0; } +.status-card.bottomless .status-card__image, +.status-card.bottomless .status-card__image-image, +.status-card.bottomless .status-card__image-preview { + border-end-end-radius: 0; + border-end-start-radius: 0; +} + .status-card.expanded > a { width: 100%; } @@ -10229,6 +10241,7 @@ noscript { } .more-from-author { + box-sizing: border-box; font-size: 14px; color: $darker-text-color; background: var(--surface-background-color); From a5a15846756dd62e01bf7eb64fdf3b8fafc3ba69 Mon Sep 17 00:00:00 2001 From: Sujay Date: Wed, 12 Jun 2024 19:18:30 +0530 Subject: [PATCH 397/658] Update README.md (#30626) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4aca37673b..9c0b0d20ed 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre ### Tech stack - **Ruby on Rails** powers the REST API and other web pages -- **React.js** and Redux are used for the dynamic parts of the interface +- **React.js** and **Redux** are used for the dynamic parts of the interface - **Node.js** powers the streaming API ### Requirements From bf56e982a9c211396efea16f2ee596102b36db3f Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 12 Jun 2024 15:50:38 +0200 Subject: [PATCH 398/658] Fix notifications from limited users being outright dropped (#30559) --- app/lib/feed_manager.rb | 5 +---- spec/lib/feed_manager_spec.rb | 6 +++--- spec/services/notify_service_spec.rb | 29 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 95a687fa41..1fb224a133 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -420,10 +420,7 @@ class FeedManager check_for_blocks = status.active_mentions.pluck(:account_id) check_for_blocks.push(status.in_reply_to_account) if status.reply? && !status.in_reply_to_account_id.nil? - should_filter = blocks_or_mutes?(receiver_id, check_for_blocks, :mentions) # Filter if it's from someone I blocked, in reply to someone I blocked, or mentioning someone I blocked (or muted) - should_filter ||= status.account.silenced? && !Follow.exists?(account_id: receiver_id, target_account_id: status.account_id) # Filter if the account is silenced and I'm not following them - - should_filter + blocks_or_mutes?(receiver_id, check_for_blocks, :mentions) # Filter if it's from someone I blocked, in reply to someone I blocked, or mentioning someone I blocked (or muted) end # Check if status should not be added to the list feed diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb index 613bcb3045..679309bd11 100644 --- a/spec/lib/feed_manager_spec.rb +++ b/spec/lib/feed_manager_spec.rb @@ -206,13 +206,13 @@ RSpec.describe FeedManager do expect(described_class.instance.filter?(:mentions, reply, bob)).to be true end - it 'returns true for status by silenced account who recipient is not following' do + it 'returns false for status by limited account who recipient is not following' do status = Fabricate(:status, text: 'Hello world', account: alice) alice.silence! - expect(described_class.instance.filter?(:mentions, status, bob)).to be true + expect(described_class.instance.filter?(:mentions, status, bob)).to be false end - it 'returns false for status by followed silenced account' do + it 'returns false for status by followed limited account' do status = Fabricate(:status, text: 'Hello world', account: alice) alice.silence! bob.follow!(alice) diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index 6064d2b050..8c810f1c32 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -129,6 +129,35 @@ RSpec.describe NotifyService do end end + describe NotifyService::DismissCondition do + subject { described_class.new(notification) } + + let(:activity) { Fabricate(:mention, status: Fabricate(:status)) } + let(:notification) { Fabricate(:notification, type: :mention, activity: activity, from_account: activity.status.account, account: activity.account) } + + describe '#dismiss?' do + context 'when sender is silenced' do + before do + notification.from_account.silence! + end + + it 'returns false' do + expect(subject.dismiss?).to be false + end + end + + context 'when recipient has blocked sender' do + before do + notification.account.block!(notification.from_account) + end + + it 'returns true' do + expect(subject.dismiss?).to be true + end + end + end + end + describe NotifyService::FilterCondition do subject { described_class.new(notification) } From 7ad5a3a2b728229704e29819b3b87bc0ccdc473f Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Thu, 13 Jun 2024 10:21:50 +0200 Subject: [PATCH 399/658] Disable `consistent-return` eslint rule for Typescript files (#30675) --- .eslintrc.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index 759003b55e..e3afb1c9f2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -349,6 +349,9 @@ module.exports = defineConfig({ // Disable formatting rules that have been enabled in the base config 'indent': 'off', + // This is not needed as we use noImplicitReturns, which handles this in addition to understanding types + 'consistent-return': 'off', + 'import/consistent-type-specifier-style': ['error', 'prefer-top-level'], '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'], From fc2f49cfbcbe996abeb267592bcf39d60d2995ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:26:00 +0200 Subject: [PATCH 400/658] chore(deps): update docker.io/ruby docker tag to v3.3.3 (#30679) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2dc7602b2d..e29377829c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ ARG BUILDPLATFORM=${BUILDPLATFORM} # Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"] # renovate: datasource=docker depName=docker.io/ruby -ARG RUBY_VERSION="3.3.2" +ARG RUBY_VERSION="3.3.3" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] # renovate: datasource=node-version depName=node ARG NODE_MAJOR_VERSION="20" From b379dc156e9a2292f2e21f80543c0b80d4087688 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Jun 2024 04:26:09 -0400 Subject: [PATCH 401/658] Update parser to version 3.3.3.0 (#30676) --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 902ddd5f59..222aaff504 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -584,7 +584,7 @@ GEM orm_adapter (0.5.0) ox (2.14.18) parallel (1.25.1) - parser (3.3.2.0) + parser (3.3.3.0) ast (~> 2.4.1) racc parslet (2.0.0) From fe740455767a361798df3a21791f9db8e2056f7e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:26:17 +0200 Subject: [PATCH 402/658] chore(deps): update dependency ruby to v3.3.3 (#30667) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 4772543317..619b537668 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.2 +3.3.3 From 37f53542fe1c36c6126932cbb3840f6d4659104e Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 13 Jun 2024 14:42:40 +0200 Subject: [PATCH 403/658] Fix limit handling in grouped notifications CTE (#30685) --- app/models/notification.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/notification.rb b/app/models/notification.rb index e3deaa5348..01abe74f5e 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -152,6 +152,7 @@ class Notification < ApplicationRecord .limit(1), query .joins('CROSS JOIN grouped_notifications') + .where('array_length(grouped_notifications.groups, 1) < :limit', limit: limit) .where('notifications.id < grouped_notifications.id') .where.not("COALESCE(notifications.group_key, 'ungrouped-' || notifications.id) = ANY(grouped_notifications.groups)") .select('notifications.*', "array_append(grouped_notifications.groups, COALESCE(notifications.group_key, 'ungrouped-' || notifications.id))") @@ -179,6 +180,7 @@ class Notification < ApplicationRecord .limit(1), query .joins('CROSS JOIN grouped_notifications') + .where('array_length(grouped_notifications.groups, 1) < :limit', limit: limit) .where('notifications.id > grouped_notifications.id') .where.not("COALESCE(notifications.group_key, 'ungrouped-' || notifications.id) = ANY(grouped_notifications.groups)") .select('notifications.*', "array_append(grouped_notifications.groups, COALESCE(notifications.group_key, 'ungrouped-' || notifications.id))") From ed6d24330ba2f80b99428cb8ee19e5d8400ebd16 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 13 Jun 2024 15:04:16 +0200 Subject: [PATCH 404/658] Add author links on the explore page in web UI (#30521) --- .../mastodon/actions/importer/index.js | 8 +- .../mastodon/actions/importer/normalizer.js | 4 + app/javascript/mastodon/actions/trends.js | 9 +- .../mastodon/components/more_from_author.jsx | 19 +++ .../explore/components/author_link.jsx | 21 ++++ .../features/explore/components/story.jsx | 110 +++++++++++------- .../mastodon/features/explore/links.jsx | 3 +- .../features/status/components/card.jsx | 19 +-- app/javascript/mastodon/locales/en.json | 1 + .../styles/mastodon/components.scss | 69 ++++++++--- app/javascript/styles/mastodon/variables.scss | 2 + 11 files changed, 185 insertions(+), 80 deletions(-) create mode 100644 app/javascript/mastodon/components/more_from_author.jsx create mode 100644 app/javascript/mastodon/features/explore/components/author_link.jsx diff --git a/app/javascript/mastodon/actions/importer/index.js b/app/javascript/mastodon/actions/importer/index.js index 16f191b584..d906bdfb14 100644 --- a/app/javascript/mastodon/actions/importer/index.js +++ b/app/javascript/mastodon/actions/importer/index.js @@ -68,13 +68,17 @@ export function importFetchedStatuses(statuses) { status.filtered.forEach(result => pushUnique(filters, result.filter)); } - if (status.reblog && status.reblog.id) { + if (status.reblog?.id) { processStatus(status.reblog); } - if (status.poll && status.poll.id) { + if (status.poll?.id) { pushUnique(polls, normalizePoll(status.poll, getState().getIn(['polls', status.poll.id]))); } + + if (status.card?.author_account) { + pushUnique(accounts, status.card.author_account); + } } statuses.forEach(processStatus); diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js index b5a30343e4..be76b0f391 100644 --- a/app/javascript/mastodon/actions/importer/normalizer.js +++ b/app/javascript/mastodon/actions/importer/normalizer.js @@ -36,6 +36,10 @@ export function normalizeStatus(status, normalOldStatus) { normalStatus.poll = status.poll.id; } + if (status.card?.author_account) { + normalStatus.card = { ...status.card, author_account: status.card.author_account.id }; + } + if (status.filtered) { normalStatus.filtered = status.filtered.map(normalizeFilterResult); } diff --git a/app/javascript/mastodon/actions/trends.js b/app/javascript/mastodon/actions/trends.js index 0b840b41ce..01089fccbb 100644 --- a/app/javascript/mastodon/actions/trends.js +++ b/app/javascript/mastodon/actions/trends.js @@ -1,6 +1,6 @@ import api, { getLinks } from '../api'; -import { importFetchedStatuses } from './importer'; +import { importFetchedStatuses, importFetchedAccounts } from './importer'; export const TRENDS_TAGS_FETCH_REQUEST = 'TRENDS_TAGS_FETCH_REQUEST'; export const TRENDS_TAGS_FETCH_SUCCESS = 'TRENDS_TAGS_FETCH_SUCCESS'; @@ -49,8 +49,11 @@ export const fetchTrendingLinks = () => (dispatch) => { dispatch(fetchTrendingLinksRequest()); api() - .get('/api/v1/trends/links') - .then(({ data }) => dispatch(fetchTrendingLinksSuccess(data))) + .get('/api/v1/trends/links', { params: { limit: 20 } }) + .then(({ data }) => { + dispatch(importFetchedAccounts(data.map(link => link.author_account).filter(account => !!account))); + dispatch(fetchTrendingLinksSuccess(data)); + }) .catch(err => dispatch(fetchTrendingLinksFail(err))); }; diff --git a/app/javascript/mastodon/components/more_from_author.jsx b/app/javascript/mastodon/components/more_from_author.jsx new file mode 100644 index 0000000000..c20e76ac45 --- /dev/null +++ b/app/javascript/mastodon/components/more_from_author.jsx @@ -0,0 +1,19 @@ +import PropTypes from 'prop-types'; + +import { FormattedMessage } from 'react-intl'; + +import { AuthorLink } from 'mastodon/features/explore/components/author_link'; + +export const MoreFromAuthor = ({ accountId }) => ( +
+ + + + + }} /> +
+); + +MoreFromAuthor.propTypes = { + accountId: PropTypes.string.isRequired, +}; diff --git a/app/javascript/mastodon/features/explore/components/author_link.jsx b/app/javascript/mastodon/features/explore/components/author_link.jsx new file mode 100644 index 0000000000..b9dec3367e --- /dev/null +++ b/app/javascript/mastodon/features/explore/components/author_link.jsx @@ -0,0 +1,21 @@ +import PropTypes from 'prop-types'; + +import { Link } from 'react-router-dom'; + +import { Avatar } from 'mastodon/components/avatar'; +import { useAppSelector } from 'mastodon/store'; + +export const AuthorLink = ({ accountId }) => { + const account = useAppSelector(state => state.getIn(['accounts', accountId])); + + return ( + + + + + ); +}; + +AuthorLink.propTypes = { + accountId: PropTypes.string.isRequired, +}; diff --git a/app/javascript/mastodon/features/explore/components/story.jsx b/app/javascript/mastodon/features/explore/components/story.jsx index 80dd5200fc..a2cae942d4 100644 --- a/app/javascript/mastodon/features/explore/components/story.jsx +++ b/app/javascript/mastodon/features/explore/components/story.jsx @@ -1,61 +1,89 @@ import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; +import { useState, useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; + import { Blurhash } from 'mastodon/components/blurhash'; -import { accountsCountRenderer } from 'mastodon/components/hashtag'; import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; import { ShortNumber } from 'mastodon/components/short_number'; import { Skeleton } from 'mastodon/components/skeleton'; -export default class Story extends PureComponent { +import { AuthorLink } from './author_link'; - static propTypes = { - url: PropTypes.string, - title: PropTypes.string, - lang: PropTypes.string, - publisher: PropTypes.string, - publishedAt: PropTypes.string, - author: PropTypes.string, - sharedTimes: PropTypes.number, - thumbnail: PropTypes.string, - thumbnailDescription: PropTypes.string, - blurhash: PropTypes.string, - expanded: PropTypes.bool, - }; +const sharesCountRenderer = (displayNumber, pluralReady) => ( + {displayNumber}, + }} + /> +); - state = { - thumbnailLoaded: false, - }; +export const Story = ({ + url, + title, + lang, + publisher, + publishedAt, + author, + authorAccount, + sharedTimes, + thumbnail, + thumbnailDescription, + blurhash, + expanded +}) => { + const [thumbnailLoaded, setThumbnailLoaded] = useState(false); - handleImageLoad = () => this.setState({ thumbnailLoaded: true }); + const handleImageLoad = useCallback(() => { + setThumbnailLoaded(true); + }, [setThumbnailLoaded]); - render () { - const { expanded, url, title, lang, publisher, author, publishedAt, sharedTimes, thumbnail, thumbnailDescription, blurhash } = this.props; - - const { thumbnailLoaded } = this.state; - - return ( - -
-
{publisher ? {publisher} : }{publishedAt && <> · }
-
{title ? title : }
-
{author && <>{author} }} /> · }{typeof sharedTimes === 'number' ? : }
+ return ( +
+ + ); +}; -} +Story.propTypes = { + url: PropTypes.string, + title: PropTypes.string, + lang: PropTypes.string, + publisher: PropTypes.string, + publishedAt: PropTypes.string, + author: PropTypes.string, + authorAccount: PropTypes.string, + sharedTimes: PropTypes.number, + thumbnail: PropTypes.string, + thumbnailDescription: PropTypes.string, + blurhash: PropTypes.string, + expanded: PropTypes.bool, +}; diff --git a/app/javascript/mastodon/features/explore/links.jsx b/app/javascript/mastodon/features/explore/links.jsx index 9e143b4505..93fd1fb6dd 100644 --- a/app/javascript/mastodon/features/explore/links.jsx +++ b/app/javascript/mastodon/features/explore/links.jsx @@ -13,7 +13,7 @@ import { DismissableBanner } from 'mastodon/components/dismissable_banner'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; -import Story from './components/story'; +import { Story } from './components/story'; const mapStateToProps = state => ({ links: state.getIn(['trends', 'links', 'items']), @@ -75,6 +75,7 @@ class Links extends PureComponent { publisher={link.get('provider_name')} publishedAt={link.get('published_at')} author={link.get('author_name')} + authorAccount={link.getIn(['author_account', 'id'])} sharedTimes={link.getIn(['history', 0, 'accounts']) * 1 + link.getIn(['history', 1, 'accounts']) * 1} thumbnail={link.get('image')} thumbnailDescription={link.get('image_description')} diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index c2f5703b3c..f562e53f0b 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -6,7 +6,6 @@ import { PureComponent } from 'react'; import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; -import { Link } from 'react-router-dom'; import Immutable from 'immutable'; @@ -15,9 +14,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import DescriptionIcon from '@/material-icons/400-24px/description-fill.svg?react'; import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react'; import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react'; -import { Avatar } from 'mastodon/components/avatar'; import { Blurhash } from 'mastodon/components/blurhash'; import { Icon } from 'mastodon/components/icon'; +import { MoreFromAuthor } from 'mastodon/components/more_from_author'; import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; import { useBlurhash } from 'mastodon/initial_state'; @@ -59,20 +58,6 @@ const addAutoPlay = html => { return html; }; -const MoreFromAuthor = ({ author }) => ( -
- - - - - {author.get('display_name')} }} /> -
-); - -MoreFromAuthor.propTypes = { - author: ImmutablePropTypes.map, -}; - export default class Card extends PureComponent { static propTypes = { @@ -259,7 +244,7 @@ export default class Card extends PureComponent { {description} - {showAuthor && } + {showAuthor && } ); } diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 63298d59e3..4f5caeb6ac 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -415,6 +415,7 @@ "limited_account_hint.title": "This profile has been hidden by the moderators of {domain}.", "link_preview.author": "By {name}", "link_preview.more_from_author": "More from {name}", + "link_preview.shares": "{count, plural, one {{counter} post} other {{counter} posts}}", "lists.account.add": "Add to list", "lists.account.remove": "Remove from list", "lists.delete": "Delete list", diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 2400f319db..d5c3d2605c 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -8796,43 +8796,80 @@ noscript { display: flex; align-items: center; color: $primary-text-color; - text-decoration: none; - padding: 15px; + padding: 16px; border-bottom: 1px solid var(--background-border-color); - gap: 15px; + gap: 16px; &:last-child { border-bottom: 0; } - &:hover, - &:active, - &:focus { - color: $highlight-text-color; - - .story__details__publisher, - .story__details__shared { - color: $highlight-text-color; - } - } - &__details { flex: 1 1 auto; &__publisher { color: $darker-text-color; margin-bottom: 8px; + font-size: 14px; + line-height: 20px; } &__title { + display: block; font-size: 19px; line-height: 24px; font-weight: 500; margin-bottom: 8px; + text-decoration: none; + color: $primary-text-color; + + &:hover, + &:active, + &:focus { + color: $highlight-text-color; + } } &__shared { + display: flex; + align-items: center; color: $darker-text-color; + gap: 8px; + justify-content: space-between; + font-size: 14px; + line-height: 20px; + + & > span { + display: flex; + align-items: center; + gap: 4px; + } + + &__pill { + background: var(--surface-variant-background-color); + border-radius: 4px; + color: inherit; + text-decoration: none; + padding: 4px 12px; + font-size: 12px; + font-weight: 500; + line-height: 16px; + } + + &__author-link { + display: inline-flex; + align-items: center; + gap: 4px; + color: $primary-text-color; + font-weight: 500; + text-decoration: none; + + &:hover, + &:active, + &:focus { + color: $highlight-text-color; + } + } } strong { @@ -9903,14 +9940,14 @@ noscript { color: inherit; text-decoration: none; padding: 4px 12px; - background: $ui-base-color; + background: var(--surface-variant-background-color); border-radius: 4px; font-weight: 500; &:hover, &:focus, &:active { - background: lighten($ui-base-color, 4%); + background: var(--surface-variant-active-background-color); } } diff --git a/app/javascript/styles/mastodon/variables.scss b/app/javascript/styles/mastodon/variables.scss index 58b9dd9b61..2848a42b3f 100644 --- a/app/javascript/styles/mastodon/variables.scss +++ b/app/javascript/styles/mastodon/variables.scss @@ -106,4 +106,6 @@ $font-monospace: 'mastodon-font-monospace' !default; --background-color: #{darken($ui-base-color, 8%)}; --background-color-tint: #{rgba(darken($ui-base-color, 8%), 0.9)}; --surface-background-color: #{darken($ui-base-color, 4%)}; + --surface-variant-background-color: #{$ui-base-color}; + --surface-variant-active-background-color: #{lighten($ui-base-color, 4%)}; } From 64fc17352bec11684cf617b10ebc5a11eb7ec924 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 15:13:06 +0200 Subject: [PATCH 405/658] chore(deps): update dependency sanitize to v6.1.1 (#30683) 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 222aaff504..89425363db 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -772,7 +772,7 @@ GEM fugit (~> 1.1, >= 1.1.6) safety_net_attestation (0.4.0) jwt (~> 2.0) - sanitize (6.1.0) + sanitize (6.1.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) scenic (1.8.0) From 474dda70272b9e406fb4a22b1f66caf797c2f8b2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 15:15:01 +0200 Subject: [PATCH 406/658] chore(deps): update dependency aws-sdk-s3 to v1.152.2 (#30680) 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 89425363db..172b7cbdd4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,7 +109,7 @@ GEM aws-sdk-kms (1.83.0) aws-sdk-core (~> 3, >= 3.197.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.152.1) + aws-sdk-s3 (1.152.2) aws-sdk-core (~> 3, >= 3.197.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) From 3b7c50abca213353f6e210837fda0f21baf1be20 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Jun 2024 09:15:32 -0400 Subject: [PATCH 407/658] Remove bundler-audit ignore config (#30672) --- .bundler-audit.yml | 6 ------ .github/workflows/bundler-audit.yml | 2 -- 2 files changed, 8 deletions(-) delete mode 100644 .bundler-audit.yml diff --git a/.bundler-audit.yml b/.bundler-audit.yml deleted file mode 100644 index 0671df390f..0000000000 --- a/.bundler-audit.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -ignore: - # devise-two-factor advisory about brute-forcing TOTP - # We have rate-limits on authentication endpoints in place (including second - # factor verification) since Mastodon v3.2.0 - - CVE-2024-0227 diff --git a/.github/workflows/bundler-audit.yml b/.github/workflows/bundler-audit.yml index 923abcd91c..48f9d82933 100644 --- a/.github/workflows/bundler-audit.yml +++ b/.github/workflows/bundler-audit.yml @@ -6,14 +6,12 @@ on: paths: - 'Gemfile*' - '.ruby-version' - - '.bundler-audit.yml' - '.github/workflows/bundler-audit.yml' pull_request: paths: - 'Gemfile*' - '.ruby-version' - - '.bundler-audit.yml' - '.github/workflows/bundler-audit.yml' schedule: From 8889816a51df17e2e78cdcaa17bda0780393bd0d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Jun 2024 09:23:32 -0400 Subject: [PATCH 408/658] Use stock ruby environment on CI lint tasks (#30657) --- .github/workflows/bundler-audit.yml | 9 +++++++-- .github/workflows/lint-haml.yml | 10 ++++++++-- .github/workflows/lint-ruby.yml | 9 +++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.github/workflows/bundler-audit.yml b/.github/workflows/bundler-audit.yml index 48f9d82933..e3e2da0c78 100644 --- a/.github/workflows/bundler-audit.yml +++ b/.github/workflows/bundler-audit.yml @@ -21,12 +21,17 @@ jobs: security: runs-on: ubuntu-latest + env: + BUNDLE_ONLY: development + steps: - name: Clone repository uses: actions/checkout@v4 - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true - name: Run bundler-audit run: bundle exec bundler-audit check --update diff --git a/.github/workflows/lint-haml.yml b/.github/workflows/lint-haml.yml index 25615b720d..ca4b0c80bf 100644 --- a/.github/workflows/lint-haml.yml +++ b/.github/workflows/lint-haml.yml @@ -26,12 +26,18 @@ on: jobs: lint: runs-on: ubuntu-latest + + env: + BUNDLE_ONLY: development + steps: - name: Clone repository uses: actions/checkout@v4 - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true - name: Run haml-lint run: | diff --git a/.github/workflows/lint-ruby.yml b/.github/workflows/lint-ruby.yml index 411b323486..2e4de55725 100644 --- a/.github/workflows/lint-ruby.yml +++ b/.github/workflows/lint-ruby.yml @@ -27,12 +27,17 @@ jobs: lint: runs-on: ubuntu-latest + env: + BUNDLE_ONLY: development + steps: - name: Clone repository uses: actions/checkout@v4 - - name: Set up Ruby environment - uses: ./.github/actions/setup-ruby + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true - name: Set-up RuboCop Problem Matcher uses: r7kamura/rubocop-problem-matchers-action@v1 From dd587d29b68ee8548cd91697ba85b1ee274845d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 15:30:07 +0200 Subject: [PATCH 409/658] New Crowdin Translations (automated) (#30684) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ur.json | 4 +--- config/locales/activerecord.ur.yml | 26 +++++++++++++++++++++++++ config/locales/doorkeeper.cs.yml | 1 + config/locales/doorkeeper.ia.yml | 2 ++ config/locales/doorkeeper.sl.yml | 2 ++ config/locales/doorkeeper.sv.yml | 1 + config/locales/simple_form.sv.yml | 2 ++ config/locales/sv.yml | 1 + 8 files changed, 36 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/ur.json b/app/javascript/mastodon/locales/ur.json index 6f3debae2e..1b9f8d9691 100644 --- a/app/javascript/mastodon/locales/ur.json +++ b/app/javascript/mastodon/locales/ur.json @@ -28,7 +28,7 @@ "account.follow": "پیروی کریں", "account.follow_back": "اکاؤنٹ کو فالو بیک ", "account.followers": "پیروکار", - "account.followers.empty": "\"ہنوز اس صارف کی کوئی پیروی نہیں کرتا\".", + "account.followers.empty": "ہنوز اس صارف کی کوئی پیروی نہیں کرتا.", "account.followers_counter": "{count, plural,one {{counter} پیروکار} other {{counter} پیروکار}}", "account.following": "فالو کر رہے ہیں", "account.following_counter": "{count, plural, one {{counter} پیروی کر رہے ہیں} other {{counter} پیروی کر رہے ہیں}}", @@ -66,11 +66,9 @@ "account.unmute": "@{name} کو با آواز کریں", "account.unmute_notifications_short": "نوٹیفیکیشنز کو خاموش نہ کریں", "account.unmute_short": "کو خاموش نہ کریں", - "account_note.placeholder": "Click to add a note", "admin.dashboard.daily_retention": "ایڈمن ڈیش بورڈ کو ڈیلی چیک ان کریں", "admin.dashboard.monthly_retention": "ایڈمن کیش بورڈ کو منتھلی چیک ان کریں", "admin.dashboard.retention.average": "اوسط", - "admin.dashboard.retention.cohort": "Sign-up month", "admin.dashboard.retention.cohort_size": "نئے یسرز", "alert.rate_limited.message": "\"{retry_time, time, medium} کے بعد کوشش کریں\".", "alert.rate_limited.title": "محدود شرح", diff --git a/config/locales/activerecord.ur.yml b/config/locales/activerecord.ur.yml index 2cace5883d..e8fbef9afc 100644 --- a/config/locales/activerecord.ur.yml +++ b/config/locales/activerecord.ur.yml @@ -1 +1,27 @@ +--- ur: + activerecord: + attributes: + poll: + expires_at: ڈیڈ لائن + options: اپنی مرضی + user: + agreement: سروس کا معاہدہ + email: ای میل ایڈریسز + locale: لوکل + password: پاس ورڈ + user/account: + username: یوزر نیم + user/invite_request: + text: وجہ + errors: + models: + account: + attributes: + username: + invalid: صرف حروف، نمبر اور انڈر سکور پر مشتمل ہونا چاہیے۔ + reserved: محفوظ ہے + admin/webhook: + attributes: + url: + invalid: ایک درست URL نہیں ہے۔ diff --git a/config/locales/doorkeeper.cs.yml b/config/locales/doorkeeper.cs.yml index be2a4d971a..3323834685 100644 --- a/config/locales/doorkeeper.cs.yml +++ b/config/locales/doorkeeper.cs.yml @@ -135,6 +135,7 @@ cs: media: Mediální přílohy mutes: Skrytí notifications: Oznámení + profile: Váš Mastodon profil push: Push oznámení reports: Hlášení search: Hledání diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index 5b99abb7b4..985d073ab8 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -135,6 +135,7 @@ ia: media: Annexos multimedial mutes: Silentiates notifications: Notificationes + profile: Tu profilo de Mastodon push: Notificationes push reports: Reportos search: Cercar @@ -165,6 +166,7 @@ ia: admin:write:reports: exequer actiones de moderation sur reportos crypto: usar cryptation de puncta a puncta follow: modificar relationes inter contos + profile: leger solmente le information de profilo de tu conto push: reciper tu notificationes push read: leger tote le datos de tu conto read:accounts: vider informationes de contos diff --git a/config/locales/doorkeeper.sl.yml b/config/locales/doorkeeper.sl.yml index a613308b28..f6f64fc87f 100644 --- a/config/locales/doorkeeper.sl.yml +++ b/config/locales/doorkeeper.sl.yml @@ -135,6 +135,7 @@ sl: media: Predstavnostne priloge mutes: Utišani notifications: Obvestila + profile: Vaš profil Mastodon push: Potisna obvestila reports: Prijave search: Iskanje @@ -165,6 +166,7 @@ sl: admin:write:reports: izvedi moderirana dejanja na prijavah crypto: Uporabi šifriranje od konca do konca follow: spremeni razmerja med računi + profile: preberi le podatke profila računa push: prejmi potisna obvestila read: preberi vse podatke svojega računa read:accounts: oglejte si podrobnosti računov diff --git a/config/locales/doorkeeper.sv.yml b/config/locales/doorkeeper.sv.yml index bc4ba6f53e..b46c16d4de 100644 --- a/config/locales/doorkeeper.sv.yml +++ b/config/locales/doorkeeper.sv.yml @@ -166,6 +166,7 @@ sv: admin:write:reports: utföra modereringsåtgärder på rapporter crypto: använd obruten kryptering follow: modifiera kontorelationer + profile: läs endast ditt kontos profilinformation push: ta emot dina push-notiser read: läsa dina kontodata read:accounts: se kontoinformation diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml index 5e5c6f9549..11d142a2bd 100644 --- a/config/locales/simple_form.sv.yml +++ b/config/locales/simple_form.sv.yml @@ -77,11 +77,13 @@ sv: warn: Dölj det filtrerade innehållet bakom en varning som visar filtrets rubrik form_admin_settings: activity_api_enabled: Antalet lokalt publicerade inlägg, aktiva användare och nya registrerade konton per vecka + app_icon: WEBP, PNG, GIF eller JPG. Använd istället för appens egna ikon på mobila enheter. backups_retention_period: Användare har möjlighet att generera arkiv av sina inlägg för att ladda ned senare. När det sätts till ett positivt värde raderas dessa arkiv automatiskt från din lagring efter det angivna antalet dagar. bootstrap_timeline_accounts: Dessa konton kommer fästas högst upp i nya användares följrekommendationer. closed_registrations_message: Visas när nyregistreringar är avstängda content_cache_retention_period: Alla inlägg från andra servrar (inklusive booster och svar) kommer att raderas efter det angivna antalet dagar, utan hänsyn till någon lokal användarinteraktion med dessa inlägg. Detta inkluderar inlägg där en lokal användare har markerat det som bokmärke eller favoriter. Privata omnämnanden mellan användare från olika instanser kommer också att gå förlorade och blir omöjliga att återställa. Användningen av denna inställning är avsedd för specialfall och bryter många användarförväntningar när de implementeras för allmänt bruk. custom_css: Du kan använda anpassade stilar på webbversionen av Mastodon. + favicon: WEBP, PNG, GIF eller JPG. Används på mobila enheter istället för appens egen ikon. mascot: Åsidosätter illustrationen i det avancerade webbgränssnittet. media_cache_retention_period: Mediafiler från inlägg som gjorts av fjärranvändare cachas på din server. När inställd på ett positivt värde kommer media att raderas efter det angivna antalet dagar. Om mediadatat begärs efter att det har raderats, kommer det att laddas ned igen om källinnehållet fortfarande är tillgängligt. På grund av begränsningar för hur ofta förhandsgranskningskort för länkar hämtas från tredjepartswebbplatser, rekommenderas det att ange detta värde till minst 14 dagar, annars kommer förhandsgranskningskorten inte att uppdateras på begäran före den tiden. peers_api_enabled: En lista över domänen den här servern har stött på i fediversum. Ingen data inkluderas om du har federerat med servern, bara att din server känner till den. Detta används av tjänster som samlar statistik om federering i allmänhet. diff --git a/config/locales/sv.yml b/config/locales/sv.yml index cf68cdd563..a3d31547ce 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -951,6 +951,7 @@ sv: delete: Radera edit_preset: Redigera varningsförval empty: Du har inte definierat några varningsförval ännu. + title: Varning förinställningar webhooks: add_new: Lägg till slutpunkt delete: Ta bort From 45abddb302a44adafdcc0479cc93dea4d8fb4b64 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 13 Jun 2024 16:10:34 +0200 Subject: [PATCH 410/658] Fix pagination attributes not being returned in ungroupable-only pages (#30688) --- app/serializers/rest/notification_group_serializer.rb | 2 +- spec/requests/api/v2_alpha/notifications_spec.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/serializers/rest/notification_group_serializer.rb b/app/serializers/rest/notification_group_serializer.rb index 05b51b07a5..ce1950c5a4 100644 --- a/app/serializers/rest/notification_group_serializer.rb +++ b/app/serializers/rest/notification_group_serializer.rb @@ -45,6 +45,6 @@ class REST::NotificationGroupSerializer < ActiveModel::Serializer end def paginated? - instance_options[:group_metadata].present? + !instance_options[:group_metadata].nil? end end diff --git a/spec/requests/api/v2_alpha/notifications_spec.rb b/spec/requests/api/v2_alpha/notifications_spec.rb index 9bd1a32e9b..ac44605ac5 100644 --- a/spec/requests/api/v2_alpha/notifications_spec.rb +++ b/spec/requests/api/v2_alpha/notifications_spec.rb @@ -58,6 +58,7 @@ RSpec.describe 'Notifications' do expect(response).to have_http_status(200) expect(body_json_types.uniq).to eq ['mention'] + expect(body_as_json[0][:page_min_id]).to_not be_nil end end From 3a191b3797dde1daf79cd748a14b87240532d543 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 13 Jun 2024 10:27:17 -0400 Subject: [PATCH 411/658] Add `rubocop` binstub, simplify configuration (#30407) --- .github/workflows/lint-ruby.yml | 2 +- .rubocop.yml | 254 ++++---------------------------- .rubocop/custom.yml | 6 + .rubocop/layout.yml | 6 + .rubocop/metrics.yml | 23 +++ .rubocop/naming.yml | 3 + .rubocop/rails.yml | 27 ++++ .rubocop/rspec.yml | 17 +++ .rubocop/rspec_rails.yml | 3 + .rubocop/strict.yml | 19 +++ .rubocop/style.yml | 47 ++++++ bin/rubocop | 27 ++++ lint-staged.config.js | 3 +- 13 files changed, 210 insertions(+), 227 deletions(-) create mode 100644 .rubocop/custom.yml create mode 100644 .rubocop/layout.yml create mode 100644 .rubocop/metrics.yml create mode 100644 .rubocop/naming.yml create mode 100644 .rubocop/rails.yml create mode 100644 .rubocop/rspec.yml create mode 100644 .rubocop/rspec_rails.yml create mode 100644 .rubocop/strict.yml create mode 100644 .rubocop/style.yml create mode 100755 bin/rubocop diff --git a/.github/workflows/lint-ruby.yml b/.github/workflows/lint-ruby.yml index 2e4de55725..f4e81d508b 100644 --- a/.github/workflows/lint-ruby.yml +++ b/.github/workflows/lint-ruby.yml @@ -43,7 +43,7 @@ jobs: uses: r7kamura/rubocop-problem-matchers-action@v1 - name: Run rubocop - run: bundle exec rubocop + run: bin/rubocop - name: Run brakeman if: always() # Run both checks, even if the first failed diff --git a/.rubocop.yml b/.rubocop.yml index 090b89b255..cf4ee565e0 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,34 @@ -# Can be removed once all rules are addressed or moved to this file as documented overrides -inherit_from: .rubocop_todo.yml +--- +AllCops: + CacheRootDirectory: tmp + DisplayCopNames: true + DisplayStyleGuide: true + Exclude: + - db/schema.rb + - bin/* + - node_modules/**/* + - Vagrantfile + - vendor/**/* + - config/initializers/json_ld* + - lib/mastodon/migration_helpers.rb + - lib/templates/**/* + ExtraDetails: true + NewCops: enable + TargetRubyVersion: 3.1 # Oldest supported ruby version + UseCache: true + +inherit_from: + - .rubocop/layout.yml + - .rubocop/metrics.yml + - .rubocop/naming.yml + - .rubocop/rails.yml + - .rubocop/rspec_rails.yml + - .rubocop/rspec.yml + - .rubocop/style.yml + - .rubocop/custom.yml + - .rubocop_todo.yml + - .rubocop/strict.yml -# Used for merging with exclude lists with .rubocop_todo.yml inherit_mode: merge: - Exclude @@ -12,224 +39,3 @@ require: - rubocop-rspec_rails - rubocop-performance - rubocop-capybara - - ./lib/linter/rubocop_middle_dot - -AllCops: - TargetRubyVersion: 3.1 # Set to minimum supported version of CI - DisplayCopNames: true - DisplayStyleGuide: true - ExtraDetails: true - UseCache: true - CacheRootDirectory: tmp - NewCops: enable # Opt-in to newly added rules - Exclude: - - db/schema.rb - - 'bin/*' - - 'node_modules/**/*' - - 'Vagrantfile' - - 'vendor/**/*' - - 'config/initializers/json_ld*' # Generated files - - 'lib/mastodon/migration_helpers.rb' # Vendored from GitLab - - 'lib/templates/**/*' - -# Reason: Prefer Hashes without extreme indentation -# https://docs.rubocop.org/rubocop/cops_layout.html#layoutfirsthashelementindentation -Layout/FirstHashElementIndentation: - EnforcedStyle: consistent - -# Reason: Currently disabled in .rubocop_todo.yml -# https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength -Layout/LineLength: - Max: 300 # Default of 120 causes a duplicate entry in generated todo file - -## Disable most Metrics/*Length cops -# Reason: those are often triggered and force significant refactors when this happend -# but the team feel they are not really improving the code quality. - -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsblocklength -Metrics/BlockLength: - Enabled: false - -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsclasslength -Metrics/ClassLength: - Enabled: false - -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmethodlength -Metrics/MethodLength: - Enabled: false - -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmodulelength -Metrics/ModuleLength: - Enabled: false - -## End Disable Metrics/*Length cops - -# Reason: Currently disabled in .rubocop_todo.yml -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsabcsize -Metrics/AbcSize: - Exclude: - - 'lib/mastodon/cli/*.rb' - -# Reason: Currently disabled in .rubocop_todo.yml -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricscyclomaticcomplexity -Metrics/CyclomaticComplexity: - Exclude: - - lib/mastodon/cli/*.rb - -# Reason: -# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsparameterlists -Metrics/ParameterLists: - CountKeywordArgs: false - -# Reason: Prefer seeing a variable name -# https://docs.rubocop.org/rubocop/cops_naming.html#namingblockforwarding -Naming/BlockForwarding: - EnforcedStyle: explicit - -# Reason: Prevailing style is argument file paths -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsfilepath -Rails/FilePath: - EnforcedStyle: arguments - -# Reason: Prevailing style uses numeric status codes, matches RSpec/Rails/HttpStatus -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railshttpstatus -Rails/HttpStatus: - EnforcedStyle: numeric - -# Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter -Rails/LexicallyScopedActionFilter: - Exclude: - - 'app/controllers/auth/*' - -# Reason: These tasks are doing local work which do not need full env loaded -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsrakeenvironment -Rails/RakeEnvironment: - Exclude: - - 'lib/tasks/auto_annotate_models.rake' - - 'lib/tasks/emojis.rake' - - 'lib/tasks/mastodon.rake' - - 'lib/tasks/repo.rake' - - 'lib/tasks/statistics.rake' - -# Reason: There are appropriate times to use these features -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsskipsmodelvalidations -Rails/SkipsModelValidations: - Enabled: false - -# Reason: We want to preserve the ability to migrate from arbitrary old versions, -# and cannot guarantee that every installation has run every migration as they upgrade. -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsunusedignoredcolumns -Rails/UnusedIgnoredColumns: - Enabled: false - -# Reason: Prevailing style choice -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsnegateinclude -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: -# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnamedsubject -RSpec/NamedSubject: - EnforcedStyle: named_only - -# Reason: Prevailing style choice -# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnottonot -RSpec/NotToNot: - EnforcedStyle: to_not - -# Reason: Match overrides from Rspec/FilePath rule above -# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecspecfilepathformat -RSpec/SpecFilePathFormat: - CustomTransform: - ActivityPub: activitypub - DeepL: deepl - FetchOEmbedService: fetch_oembed_service - OEmbedController: oembed_controller - OStatus: ostatus - -# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus -# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus -RSpecRails/HttpStatus: - EnforcedStyle: numeric - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#styleclassandmodulechildren -Style/ClassAndModuleChildren: - Enabled: false - -# Reason: Classes mostly self-document with their names -# https://docs.rubocop.org/rubocop/cops_style.html#styledocumentation -Style/Documentation: - Enabled: false - -# Reason: Route redirects are not token-formatted and must be skipped -# https://docs.rubocop.org/rubocop/cops_style.html#styleformatstringtoken -Style/FormatStringToken: - inherit_mode: - merge: - - AllowedMethods # The rubocop-rails config adds `redirect` - AllowedMethods: - - redirect_with_vary - -# Reason: Prevailing style choice -# https://docs.rubocop.org/rubocop/cops_style.html#stylehashaslastarrayitem -Style/HashAsLastArrayItem: - Enabled: false - -# Reason: Enforce modern Ruby style -# https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax -Style/HashSyntax: - EnforcedStyle: ruby19_no_mixed_keys - EnforcedShorthandSyntax: either - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#stylenumericliterals -Style/NumericLiterals: - AllowedPatterns: - - \d{4}_\d{2}_\d{2}_\d{6} # For DB migration date version number readability - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#stylepercentliteraldelimiters -Style/PercentLiteralDelimiters: - PreferredDelimiters: - '%i': '()' - '%w': '()' - -# Reason: Prefer less indentation in conditional assignments -# https://docs.rubocop.org/rubocop/cops_style.html#styleredundantbegin -Style/RedundantBegin: - Enabled: false - -# Reason: Prevailing style choice -# https://docs.rubocop.org/rubocop/cops_style.html#styleredundantfetchblock -Style/RedundantFetchBlock: - Enabled: false - -# Reason: Overridden to reduce implicit StandardError rescues -# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror -Style/RescueStandardError: - EnforcedStyle: implicit - -# Reason: Originally disabled for CodeClimate, and no config consensus has been found -# https://docs.rubocop.org/rubocop/cops_style.html#stylesymbolarray -Style/SymbolArray: - Enabled: false - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#styletrailingcommainarrayliteral -Style/TrailingCommaInArrayLiteral: - EnforcedStyleForMultiline: 'comma' - -# Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#styletrailingcommainhashliteral -Style/TrailingCommaInHashLiteral: - EnforcedStyleForMultiline: 'comma' - -Style/MiddleDot: - Enabled: true diff --git a/.rubocop/custom.yml b/.rubocop/custom.yml new file mode 100644 index 0000000000..63035837f8 --- /dev/null +++ b/.rubocop/custom.yml @@ -0,0 +1,6 @@ +--- +require: + - ../lib/linter/rubocop_middle_dot + +Style/MiddleDot: + Enabled: true diff --git a/.rubocop/layout.yml b/.rubocop/layout.yml new file mode 100644 index 0000000000..487879ca2c --- /dev/null +++ b/.rubocop/layout.yml @@ -0,0 +1,6 @@ +--- +Layout/FirstHashElementIndentation: + EnforcedStyle: consistent + +Layout/LineLength: + Max: 300 # Default of 120 causes a duplicate entry in generated todo file diff --git a/.rubocop/metrics.yml b/.rubocop/metrics.yml new file mode 100644 index 0000000000..89532af42a --- /dev/null +++ b/.rubocop/metrics.yml @@ -0,0 +1,23 @@ +--- +Metrics/AbcSize: + Exclude: + - lib/mastodon/cli/*.rb + +Metrics/BlockLength: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +Metrics/CyclomaticComplexity: + Exclude: + - lib/mastodon/cli/*.rb + +Metrics/MethodLength: + Enabled: false + +Metrics/ModuleLength: + Enabled: false + +Metrics/ParameterLists: + CountKeywordArgs: false diff --git a/.rubocop/naming.yml b/.rubocop/naming.yml new file mode 100644 index 0000000000..da6ad4ac57 --- /dev/null +++ b/.rubocop/naming.yml @@ -0,0 +1,3 @@ +--- +Naming/BlockForwarding: + EnforcedStyle: explicit diff --git a/.rubocop/rails.yml b/.rubocop/rails.yml new file mode 100644 index 0000000000..b83928dee6 --- /dev/null +++ b/.rubocop/rails.yml @@ -0,0 +1,27 @@ +--- +Rails/FilePath: + EnforcedStyle: arguments + +Rails/HttpStatus: + EnforcedStyle: numeric + +Rails/LexicallyScopedActionFilter: + Exclude: + - app/controllers/auth/* # Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions + +Rails/NegateInclude: + Enabled: false + +Rails/RakeEnvironment: + Exclude: # Tasks are doing local work which do not need full env loaded + - lib/tasks/auto_annotate_models.rake + - lib/tasks/emojis.rake + - lib/tasks/mastodon.rake + - lib/tasks/repo.rake + - lib/tasks/statistics.rake + +Rails/SkipsModelValidations: + Enabled: false + +Rails/UnusedIgnoredColumns: + Enabled: false # Preserve ability to migrate from arbitrary old versions diff --git a/.rubocop/rspec.yml b/.rubocop/rspec.yml new file mode 100644 index 0000000000..a6f8a7aee0 --- /dev/null +++ b/.rubocop/rspec.yml @@ -0,0 +1,17 @@ +--- +RSpec/ExampleLength: + CountAsOne: ['array', 'heredoc', 'method_call'] + +RSpec/NamedSubject: + EnforcedStyle: named_only + +RSpec/NotToNot: + EnforcedStyle: to_not + +RSpec/SpecFilePathFormat: + CustomTransform: + ActivityPub: activitypub + DeepL: deepl + FetchOEmbedService: fetch_oembed_service + OEmbedController: oembed_controller + OStatus: ostatus diff --git a/.rubocop/rspec_rails.yml b/.rubocop/rspec_rails.yml new file mode 100644 index 0000000000..993a5689ad --- /dev/null +++ b/.rubocop/rspec_rails.yml @@ -0,0 +1,3 @@ +--- +RSpecRails/HttpStatus: + EnforcedStyle: numeric diff --git a/.rubocop/strict.yml b/.rubocop/strict.yml new file mode 100644 index 0000000000..2222c6d8b9 --- /dev/null +++ b/.rubocop/strict.yml @@ -0,0 +1,19 @@ +Lint/Debugger: # Remove any `binding.pry` + Enabled: true + Exclude: [] + +RSpec/Focus: # Require full spec run on CI + Enabled: true + Exclude: [] + +Rails/Output: # Remove any `puts` debugging + Enabled: true + Exclude: [] + +Rails/FindEach: # Using `each` could impact performance, use `find_each` + Enabled: true + Exclude: [] + +Rails/UniqBeforePluck: # Require `uniq.pluck` and not `pluck.uniq` + Enabled: true + Exclude: [] diff --git a/.rubocop/style.yml b/.rubocop/style.yml new file mode 100644 index 0000000000..03e35a70ac --- /dev/null +++ b/.rubocop/style.yml @@ -0,0 +1,47 @@ +--- +Style/ClassAndModuleChildren: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/FormatStringToken: + AllowedMethods: + - redirect_with_vary # Route redirects are not token-formatted + inherit_mode: + merge: + - AllowedMethods + +Style/HashAsLastArrayItem: + Enabled: false + +Style/HashSyntax: + EnforcedShorthandSyntax: either + EnforcedStyle: ruby19_no_mixed_keys + +Style/NumericLiterals: + AllowedPatterns: + - \d{4}_\d{2}_\d{2}_\d{6} + +Style/PercentLiteralDelimiters: + PreferredDelimiters: + '%i': () + '%w': () + +Style/RedundantBegin: + Enabled: false + +Style/RedundantFetchBlock: + Enabled: false + +Style/RescueStandardError: + EnforcedStyle: implicit + +Style/SymbolArray: + Enabled: false + +Style/TrailingCommaInArrayLiteral: + EnforcedStyleForMultiline: comma + +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: comma diff --git a/bin/rubocop b/bin/rubocop new file mode 100755 index 0000000000..369a05bedb --- /dev/null +++ b/bin/rubocop @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rubocop' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rubocop", "rubocop") diff --git a/lint-staged.config.js b/lint-staged.config.js index 06fe66d11e..6740def512 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -1,7 +1,6 @@ const config = { '*': 'prettier --ignore-unknown --write', - 'Capfile|Gemfile|*.{rb,ruby,ru,rake}': - 'bundle exec rubocop --force-exclusion -a', + 'Capfile|Gemfile|*.{rb,ruby,ru,rake}': 'bin/rubocop --force-exclusion -a', '*.{js,jsx,ts,tsx}': 'eslint --fix', '*.{css,scss}': 'stylelint --fix', '*.haml': 'bundle exec haml-lint -a', From f0ca874b09e29feda0db3eb50aece86e95192575 Mon Sep 17 00:00:00 2001 From: Louis Brauer Date: Thu, 13 Jun 2024 16:37:43 +0200 Subject: [PATCH 412/658] Include crossorigin in inert css (#30687) --- app/views/layouts/application.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index ec6caa33ad..a73287959e 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -29,7 +29,7 @@ = stylesheet_pack_tag 'common', media: 'all', crossorigin: 'anonymous' = theme_style_tags current_theme -# Needed for the wicg-inert polyfill. It needs to be on it's own