diff --git a/.eslintrc.js b/.eslintrc.js index f9ddb42ae02558..ce9fb0927e4432 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -64,7 +64,6 @@ module.exports = defineConfig({ 'indent': ['error', 2], 'jsx-quotes': ['error', 'prefer-single'], 'semi': ['error', 'always'], - 'no-case-declarations': 'off', 'no-catch-shadow': 'error', 'no-console': [ 'warn', diff --git a/.github/workflows/crowdin-download-stable.yml b/.github/workflows/crowdin-download-stable.yml new file mode 100644 index 00000000000000..de21e2e58fcfff --- /dev/null +++ b/.github/workflows/crowdin-download-stable.yml @@ -0,0 +1,69 @@ +name: Crowdin / Download translations (stable branches) +on: + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + download-translations-stable: + runs-on: ubuntu-latest + if: github.repository == 'mastodon/mastodon' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Increase Git http.postBuffer + # This is needed due to a bug in Ubuntu's cURL version? + # See https://github.com/orgs/community/discussions/55820 + run: | + git config --global http.version HTTP/1.1 + git config --global http.postBuffer 157286400 + + # Download the translation files from Crowdin + - name: crowdin action + uses: crowdin/github-action@v2 + with: + upload_sources: false + upload_translations: false + download_translations: true + crowdin_branch_name: ${{ github.base_ref || github.ref_name }} + push_translations: false + create_pull_request: false + env: + CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} + + # As the files are extracted from a Docker container, they belong to root:root + # We need to fix this before the next steps + - name: Fix file permissions + run: sudo chown -R runner:docker . + + # This is needed to run the normalize step + - name: Set up Ruby environment + uses: ./.github/actions/setup-ruby + + - name: Run i18n normalize task + run: bundle exec i18n-tasks normalize + + # Create or update the pull request + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7.0.5 + with: + commit-message: 'New Crowdin translations' + title: 'New Crowdin Translations for ${{ github.base_ref || github.ref_name }} (automated)' + author: 'GitHub Actions ' + body: | + 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. + If you want to run the checks, then close and re-open it. + branch: i18n/crowdin/translations-${{ github.base_ref || github.ref_name }} + base: ${{ github.base_ref || github.ref_name }} + labels: i18n diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml index b3d908b77e8c9b..02d8a949dec541 100644 --- a/.github/workflows/crowdin-download.yml +++ b/.github/workflows/crowdin-download.yml @@ -53,7 +53,7 @@ jobs: # Create or update the pull request - name: Create Pull Request - uses: peter-evans/create-pull-request@v7.0.1 + uses: peter-evans/create-pull-request@v7.0.5 with: commit-message: 'New Crowdin translations' title: 'New Crowdin Translations (automated)' diff --git a/.github/workflows/crowdin-upload.yml b/.github/workflows/crowdin-upload.yml index d07f661ace8b26..19839648db05ea 100644 --- a/.github/workflows/crowdin-upload.yml +++ b/.github/workflows/crowdin-upload.yml @@ -32,7 +32,7 @@ jobs: upload_sources: true upload_translations: false download_translations: false - crowdin_branch_name: main + crowdin_branch_name: ${{ github.base_ref || github.ref_name }} env: CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }} diff --git a/.nvmrc b/.nvmrc index 65da8ce3917325..10fef252a9f178 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.17 +20.18 diff --git a/Dockerfile b/Dockerfile index c7c02d9b467ef9..a5e35025ae2f6f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.9 +# syntax=docker/dockerfile:1.10 # 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 @@ -214,7 +214,7 @@ FROM build AS ffmpeg # ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"] # renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg -ARG FFMPEG_VERSION=7.0.2 +ARG FFMPEG_VERSION=7.1 # ffmpeg download URL, change with [--build-arg FFMPEG_URL="https://ffmpeg.org/releases"] ARG FFMPEG_URL=https://ffmpeg.org/releases diff --git a/Gemfile.lock b/Gemfile.lock index b85d97761d2dd3..1c2bb8df083089 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,8 +100,8 @@ GEM attr_required (1.0.2) awrence (1.2.1) aws-eventstream (1.3.0) - aws-partitions (1.978.0) - aws-sdk-core (3.209.0) + aws-partitions (1.983.0) + aws-sdk-core (3.209.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.9) @@ -109,7 +109,7 @@ GEM aws-sdk-kms (1.94.0) aws-sdk-core (~> 3, >= 3.207.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.166.0) + aws-sdk-s3 (1.167.0) aws-sdk-core (~> 3, >= 3.207.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -301,7 +301,7 @@ GEM activesupport (>= 5.1) haml (>= 4.0.6) railties (>= 5.1) - haml_lint (0.58.0) + haml_lint (0.59.0) haml (>= 5.0) parallel (~> 1.10) rainbow @@ -369,7 +369,7 @@ GEM json-ld-preloaded (3.3.0) json-ld (~> 3.3) rdf (~> 3.3) - json-schema (5.0.0) + json-schema (5.0.1) addressable (~> 2.8) jsonapi-renderer (0.2.2) jwt (2.7.1) @@ -601,7 +601,7 @@ GEM actionmailer (>= 3) net-smtp premailer (~> 1.7, >= 1.7.9) - propshaft (1.0.1) + propshaft (1.1.0) actionpack (>= 7.0.0) activesupport (>= 7.0.0) rack @@ -698,7 +698,7 @@ GEM responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.3.7) + rexml (3.3.8) rotp (6.3.0) rouge (4.3.0) rpam2 (4.0.2) @@ -748,15 +748,15 @@ GEM parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) - rubocop-performance (1.21.1) + rubocop-performance (1.22.1) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rails (2.25.1) + rubocop-rails (2.26.2) activesupport (>= 4.2.0) rack (>= 1.1) - rubocop (>= 1.33.0, < 2.0) + rubocop (>= 1.52.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.0.4) + rubocop-rspec (3.1.0) rubocop (~> 1.61) rubocop-rspec_rails (2.30.0) rubocop (~> 1.61) @@ -815,7 +815,7 @@ GEM docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) - simplecov-html (0.12.3) + simplecov-html (0.13.1) simplecov-lcov (0.8.0) simplecov_json_formatter (0.1.4) stackprof (0.2.26) @@ -862,7 +862,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.9.1) - unicode-display_width (2.5.0) + unicode-display_width (2.6.0) uri (0.13.1) validate_email (0.1.6) activemodel (>= 3.0) @@ -884,7 +884,7 @@ GEM webfinger (1.2.0) activesupport httpclient (>= 2.4) - webmock (3.23.1) + webmock (3.24.0) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) diff --git a/app/controllers/admin/announcements_controller.rb b/app/controllers/admin/announcements_controller.rb index 8f9708183a81cf..12230a6506d929 100644 --- a/app/controllers/admin/announcements_controller.rb +++ b/app/controllers/admin/announcements_controller.rb @@ -6,6 +6,7 @@ class Admin::AnnouncementsController < Admin::BaseController def index authorize :announcement, :index? + @published_announcements_count = Announcement.published.async_count end def new diff --git a/app/controllers/admin/disputes/appeals_controller.rb b/app/controllers/admin/disputes/appeals_controller.rb index 5e342409b021cb..0c41553676735a 100644 --- a/app/controllers/admin/disputes/appeals_controller.rb +++ b/app/controllers/admin/disputes/appeals_controller.rb @@ -6,6 +6,7 @@ class Admin::Disputes::AppealsController < Admin::BaseController def index authorize :appeal, :index? + @pending_appeals_count = Appeal.pending.async_count @appeals = filtered_appeals.page(params[:page]) end diff --git a/app/controllers/admin/trends/links/preview_card_providers_controller.rb b/app/controllers/admin/trends/links/preview_card_providers_controller.rb index 768b79f8dbce45..5e4b4084f808d2 100644 --- a/app/controllers/admin/trends/links/preview_card_providers_controller.rb +++ b/app/controllers/admin/trends/links/preview_card_providers_controller.rb @@ -4,6 +4,7 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll def index authorize :preview_card_provider, :review? + @pending_preview_card_providers_count = PreviewCardProvider.unreviewed.async_count @preview_card_providers = filtered_preview_card_providers.page(params[:page]) @form = Trends::PreviewCardProviderBatch.new end diff --git a/app/controllers/admin/trends/tags_controller.rb b/app/controllers/admin/trends/tags_controller.rb index f5946448ae1f71..fcd23fbf66b676 100644 --- a/app/controllers/admin/trends/tags_controller.rb +++ b/app/controllers/admin/trends/tags_controller.rb @@ -4,6 +4,7 @@ class Admin::Trends::TagsController < Admin::BaseController def index authorize :tag, :review? + @pending_tags_count = Tag.pending_review.async_count @tags = filtered_tags.page(params[:page]) @form = Trends::TagBatch.new end diff --git a/app/controllers/concerns/web_app_controller_concern.rb b/app/controllers/concerns/web_app_controller_concern.rb index f930a4510e9ae1..3447bb0d5cc5d9 100644 --- a/app/controllers/concerns/web_app_controller_concern.rb +++ b/app/controllers/concerns/web_app_controller_concern.rb @@ -13,7 +13,7 @@ module WebAppControllerConcern policy = ContentSecurityPolicy.new if policy.sso_host.present? - p.form_action policy.sso_host + p.form_action policy.sso_host, -> { "https://#{request.host}/auth/auth/" } else p.form_action :none end diff --git a/app/controllers/settings/exports_controller.rb b/app/controllers/settings/exports_controller.rb index 076ed5dadb178f..263d20eaeae683 100644 --- a/app/controllers/settings/exports_controller.rb +++ b/app/controllers/settings/exports_controller.rb @@ -9,7 +9,7 @@ class Settings::ExportsController < Settings::BaseController skip_before_action :require_functional! def show - @export = Export.new(current_account) + @export_summary = ExportSummary.new(preloaded_account) @backups = current_user.backups end @@ -25,4 +25,15 @@ def create redirect_to settings_export_path end + + private + + def preloaded_account + current_account.tap do |account| + ActiveRecord::Associations::Preloader.new( + records: [account], + associations: :account_stat + ).call + end + end end diff --git a/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb b/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb index 0bff01ec2793a4..ca8d46afe48199 100644 --- a/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb +++ b/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb @@ -15,7 +15,7 @@ def show end def create - session[:new_otp_secret] = User.generate_otp_secret(32) + session[:new_otp_secret] = User.generate_otp_secret redirect_to new_settings_two_factor_authentication_confirmation_path end diff --git a/app/controllers/well_known/host_meta_controller.rb b/app/controllers/well_known/host_meta_controller.rb index 201da9fbc3b440..6dee587baf4fc8 100644 --- a/app/controllers/well_known/host_meta_controller.rb +++ b/app/controllers/well_known/host_meta_controller.rb @@ -7,7 +7,23 @@ class HostMetaController < ActionController::Base # rubocop:disable Rails/Applic def show @webfinger_template = "#{webfinger_url}?resource={uri}" expires_in 3.days, public: true - render content_type: 'application/xrd+xml', formats: [:xml] + + respond_to do |format| + format.any do + render content_type: 'application/xrd+xml', formats: [:xml] + end + + format.json do + render json: { + links: [ + { + rel: 'lrdd', + template: @webfinger_template, + }, + ], + } + end + end end end end diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb index e8d56341262cc5..51e28d8b4e9234 100644 --- a/app/helpers/admin/action_logs_helper.rb +++ b/app/helpers/admin/action_logs_helper.rb @@ -35,4 +35,11 @@ def log_target(log) end end end + + def sorted_action_log_types + Admin::ActionLogFilter::ACTION_TYPE_MAP + .keys + .map { |key| [I18n.t("admin.action_logs.action_types.#{key}"), key] } + .sort_by(&:first) + end end diff --git a/app/helpers/admin/dashboard_helper.rb b/app/helpers/admin/dashboard_helper.rb index 6096ff1381e7bb..f87fdad70832de 100644 --- a/app/helpers/admin/dashboard_helper.rb +++ b/app/helpers/admin/dashboard_helper.rb @@ -18,6 +18,11 @@ def relevant_account_ip(account, ip_query) end end + def date_range(range) + [l(range.first), l(range.last)] + .join(' - ') + end + def relevant_account_timestamp(account) timestamp, exact = if account.user_current_sign_in_at && account.user_current_sign_in_at < 24.hours.ago [account.user_current_sign_in_at, true] @@ -25,6 +30,8 @@ def relevant_account_timestamp(account) [account.user_current_sign_in_at, false] elsif account.user_pending? [account.user_created_at, true] + elsif account.suspended_at.present? && account.local? && account.user.nil? + [account.suspended_at, true] elsif account.last_status_at.present? [account.last_status_at, true] else diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a7ae4d6a0447e2..08c34a2c0b2426 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,12 +1,6 @@ # frozen_string_literal: true module ApplicationHelper - DANGEROUS_SCOPES = %w( - read - write - follow - ).freeze - RTL_LOCALES = %i( ar ckb @@ -95,8 +89,11 @@ def title Rails.env.production? ? site_title : "#{site_title} (Dev)" end - def class_for_scope(scope) - 'scope-danger' if DANGEROUS_SCOPES.include?(scope.to_s) + def label_for_scope(scope) + safe_join [ + tag.samp(scope, class: { 'scope-danger' => SessionActivation::DEFAULT_SCOPES.include?(scope.to_s) }), + tag.span(t("doorkeeper.scopes.#{scope}"), class: :hint), + ] end def can?(action, record) @@ -244,6 +241,10 @@ def mascot_url full_asset_url(instance_presenter.mascot&.file&.url || frontend_asset_path('images/elephant_ui_plane.svg')) end + def copyable_input(options = {}) + tag.input(type: :text, maxlength: 999, spellcheck: false, readonly: true, **options) + end + # glitch-soc addition to handle the multiple flavors def preload_locale_pack supported_locales = Themes.instance.flavour(current_flavour)['locales'] diff --git a/app/helpers/webfinger_helper.rb b/app/helpers/webfinger_helper.rb deleted file mode 100644 index 482f4e19eabef0..00000000000000 --- a/app/helpers/webfinger_helper.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module WebfingerHelper - def webfinger!(uri) - Webfinger.new(uri).perform - end -end diff --git a/app/javascript/flavours/glitch/actions/markers.ts b/app/javascript/flavours/glitch/actions/markers.ts index 37067dbcf7b56c..ea325109c5ea3b 100644 --- a/app/javascript/flavours/glitch/actions/markers.ts +++ b/app/javascript/flavours/glitch/actions/markers.ts @@ -37,8 +37,7 @@ export const synchronouslySubmitMarkers = createAppAsyncThunk( }); return; - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - } else if ('navigator' && 'sendBeacon' in navigator) { + } else if ('sendBeacon' in navigator) { // Failing that, we can use sendBeacon, but we have to encode the data as // FormData for DoorKeeper to recognize the token. const formData = new FormData(); diff --git a/app/javascript/flavours/glitch/actions/notification_groups.ts b/app/javascript/flavours/glitch/actions/notification_groups.ts index eebf6ce7a2b6b3..e39c9d6846b3da 100644 --- a/app/javascript/flavours/glitch/actions/notification_groups.ts +++ b/app/javascript/flavours/glitch/actions/notification_groups.ts @@ -70,6 +70,10 @@ function dispatchAssociatedRecords( const supportedGroupedNotificationTypes = ['favourite', 'reblog']; +export function shouldGroupNotificationType(type: string) { + return supportedGroupedNotificationTypes.includes(type); +} + export const fetchNotifications = createDataLoadingThunk( 'notificationGroups/fetch', async (_params, { getState }) => diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js index 7948984fba59b7..fa7af7055e6180 100644 --- a/app/javascript/flavours/glitch/actions/streaming.js +++ b/app/javascript/flavours/glitch/actions/streaming.js @@ -106,12 +106,13 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti dispatch(processNewNotificationForGroups(notificationJSON)); break; } - case 'notifications_merged': + case 'notifications_merged': { const state = getState(); if (state.notifications.top || !state.notifications.mounted) dispatch(expandNotifications({ forceLoad: true, maxId: undefined })); dispatch(refreshStaleNotificationGroups()); break; + } case 'conversation': // @ts-expect-error dispatch(updateConversations(JSON.parse(data.payload))); diff --git a/app/javascript/flavours/glitch/components/media_gallery.jsx b/app/javascript/flavours/glitch/components/media_gallery.jsx index 4d51bdcdc2b1ff..f2f8b21e3b5389 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.jsx +++ b/app/javascript/flavours/glitch/components/media_gallery.jsx @@ -198,7 +198,7 @@ class Item extends PureComponent { {visible && thumbnail} - {badges && ( + {visible && badges && (
{badges}
@@ -356,14 +356,14 @@ class MediaGallery extends PureComponent { return (
+ {children} + {(!visible || uncached) && (
{spoilerButton}
)} - {children} - {(visible && !uncached) && (
diff --git a/app/javascript/flavours/glitch/components/status_content.jsx b/app/javascript/flavours/glitch/components/status_content.jsx index d6dfd9f49025c9..a15a4df25a85ee 100644 --- a/app/javascript/flavours/glitch/components/status_content.jsx +++ b/app/javascript/flavours/glitch/components/status_content.jsx @@ -41,7 +41,7 @@ const isLinkMisleading = (link) => { case Node.TEXT_NODE: linkTextParts.push(node.textContent); break; - case Node.ELEMENT_NODE: + case Node.ELEMENT_NODE: { if (node.classList.contains('invisible')) return; const children = node.childNodes; for (let i = 0; i < children.length; i++) { @@ -49,6 +49,7 @@ const isLinkMisleading = (link) => { } break; } + } }; walk(link); diff --git a/app/javascript/flavours/glitch/features/ui/components/column_link.jsx b/app/javascript/flavours/glitch/features/ui/components/column_link.jsx index 452e810a6d8b77..b61e21d9f94b06 100644 --- a/app/javascript/flavours/glitch/features/ui/components/column_link.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/column_link.jsx @@ -15,7 +15,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text if (href) { return ( - + {active ? activeIconElement : iconElement} {text} {badgeElement} @@ -23,7 +23,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text ); } else if (to) { return ( - + {active ? activeIconElement : iconElement} {text} {badgeElement} @@ -37,7 +37,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text }; return ( // eslint-disable-next-line jsx-a11y/anchor-is-valid -- intentional to have the same look and feel as other menu items - + {iconElement} {text} {badgeElement} diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index 211402ab2a5ef5..16bfacb937f7fe 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -507,12 +507,12 @@ export default function compose(state = initialState, action) { .set('isUploadingThumbnail', false) .update('media_attachments', list => list.map(item => { if (item.get('id') === action.media.id) { - return fromJS(action.media); + return fromJS(action.media).set('unattached', item.get('unattached')); } return item; })); - case INIT_MEDIA_EDIT_MODAL: + case INIT_MEDIA_EDIT_MODAL: { const media = state.get('media_attachments').find(item => item.get('id') === action.id); return state.set('media_modal', ImmutableMap({ id: action.id, @@ -521,6 +521,7 @@ export default function compose(state = initialState, action) { focusY: media.getIn(['meta', 'focus', 'y'], 0), dirty: false, })); + } case COMPOSE_CHANGE_MEDIA_DESCRIPTION: return state.setIn(['media_modal', 'description'], action.description).setIn(['media_modal', 'dirty'], true); case COMPOSE_CHANGE_MEDIA_FOCUS: @@ -575,7 +576,7 @@ export default function compose(state = initialState, action) { })); case COMPOSE_DOODLE_SET: return state.mergeIn(['doodle'], action.options); - case REDRAFT: + case REDRAFT: { const do_not_federate = !!action.status.get('local_only'); let text = action.raw_text || unescapeHTML(expandMentions(action.status)); if (do_not_federate) text = text.replace(/ ?👁\ufe0f?\u200b?$/, ''); @@ -616,6 +617,7 @@ export default function compose(state = initialState, action) { })); } }); + } case COMPOSE_SET_STATUS: return state.withMutations(map => { map.set('id', action.status.get('id')); diff --git a/app/javascript/flavours/glitch/reducers/notification_groups.ts b/app/javascript/flavours/glitch/reducers/notification_groups.ts index 30f7b58737124c..3eece4b1d09a0d 100644 --- a/app/javascript/flavours/glitch/reducers/notification_groups.ts +++ b/app/javascript/flavours/glitch/reducers/notification_groups.ts @@ -21,6 +21,7 @@ import { unmountNotifications, refreshStaleNotificationGroups, pollRecentNotifications, + shouldGroupNotificationType, } from 'flavours/glitch/actions/notification_groups'; import { disconnectTimeline, @@ -205,6 +206,13 @@ function processNewNotification( groups: NotificationGroupsState['groups'], notification: ApiNotificationJSON, ) { + if (!shouldGroupNotificationType(notification.type)) { + notification = { + ...notification, + group_key: `ungrouped-${notification.id}`, + }; + } + const existingGroupIndex = groups.findIndex( (group) => group.type !== 'gap' && group.group_key === notification.group_key, @@ -242,7 +250,7 @@ function processNewNotification( groups.unshift(existingGroup); } } else { - // Create a new group + // We have not found an existing group, create a new one groups.unshift(createNotificationGroupFromNotificationJSON(notification)); } } diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js index b9773a0da65f5c..8453dd70385423 100644 --- a/app/javascript/flavours/glitch/reducers/notifications.js +++ b/app/javascript/flavours/glitch/reducers/notifications.js @@ -369,9 +369,10 @@ export default function notifications(state = initialState, action) { } return markAllForDelete(st, action.yes); - case NOTIFICATIONS_MARK_AS_READ: + case NOTIFICATIONS_MARK_AS_READ: { const lastNotification = state.get('items').find(item => item !== null); return lastNotification ? recountUnread(state, lastNotification.get('id')) : state; + } default: return state; diff --git a/app/javascript/flavours/glitch/reducers/search.js b/app/javascript/flavours/glitch/reducers/search.js index 7828d49eeedd9a..7de1c65c07a295 100644 --- a/app/javascript/flavours/glitch/reducers/search.js +++ b/app/javascript/flavours/glitch/reducers/search.js @@ -72,9 +72,10 @@ export default function search(state = initialState, action) { }); case SEARCH_EXPAND_REQUEST: return state.set('type', action.searchType).set('isLoading', true); - case SEARCH_EXPAND_SUCCESS: + case SEARCH_EXPAND_SUCCESS: { const results = action.searchType === 'hashtags' ? ImmutableOrderedSet(fromJS(action.results.hashtags)) : action.results[action.searchType].map(item => item.id); return state.updateIn(['results', action.searchType], list => list.union(results)).set('isLoading', false); + } case SEARCH_HISTORY_UPDATE: return state.set('recent', ImmutableOrderedSet(fromJS(action.recent))); default: diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index c4a16247b8dad0..9bc3c7758ea741 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -226,6 +226,10 @@ $content-width: 840px; gap: 5px; white-space: nowrap; + @media screen and (max-width: $mobile-breakpoint) { + flex: 1 0 50%; + } + &:hover, &:focus, &:active { @@ -1075,6 +1079,10 @@ a.name-tag, } } + .icon { + vertical-align: middle; + } + a.announcements-list__item__title { &:hover, &:focus, diff --git a/app/javascript/flavours/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss index 2223893336c30c..2ecc855b9c6a7d 100644 --- a/app/javascript/flavours/glitch/styles/basics.scss +++ b/app/javascript/flavours/glitch/styles/basics.scss @@ -141,6 +141,7 @@ body { width: 100%; height: auto; margin-top: -120px; + margin-bottom: -45px; } } diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 72613cbbc4874b..a17591293fd50c 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -3793,6 +3793,7 @@ $ui-header-logo-wordmark-width: 99px; overflow-y: auto; width: 100%; height: 100%; + z-index: 0; } .drawer__inner__mastodon { diff --git a/app/javascript/flavours/glitch/styles/tables.scss b/app/javascript/flavours/glitch/styles/tables.scss index c84f672a6f345e..75fc29aed5ea10 100644 --- a/app/javascript/flavours/glitch/styles/tables.scss +++ b/app/javascript/flavours/glitch/styles/tables.scss @@ -137,6 +137,7 @@ a.table-action-link { padding: 0 10px; color: $darker-text-color; font-weight: 500; + white-space: nowrap; &:hover { color: $highlight-text-color; diff --git a/app/javascript/flavours/glitch/utils/resize_image.js b/app/javascript/flavours/glitch/utils/resize_image.js index e3d4e6a354b9e9..c579fe5a2c6f1e 100644 --- a/app/javascript/flavours/glitch/utils/resize_image.js +++ b/app/javascript/flavours/glitch/utils/resize_image.js @@ -17,7 +17,7 @@ const dropOrientationIfNeeded = (orientation) => new Promise(resolve => { case false: resolve(orientation); break; - default: + default: { // black 2x1 JPEG, with the following meta information set: // - EXIF Orientation: 6 (Rotated 90° CCW) const testImageURL = @@ -39,6 +39,7 @@ const dropOrientationIfNeeded = (orientation) => new Promise(resolve => { }; img.src = testImageURL; } + } }); // Some browsers don't allow reading from a canvas and instead return all-white @@ -52,7 +53,7 @@ const checkCanvasReliability = () => new Promise((resolve, reject) => { case false: resolve(); break; - default: + default: { // 2×2 GIF with white, red, green and blue pixels const testImageURL = 'data:image/gif;base64,R0lGODdhAgACAKEDAAAA//8AAAD/AP///ywAAAAAAgACAAACA1wEBQA7'; @@ -78,6 +79,7 @@ const checkCanvasReliability = () => new Promise((resolve, reject) => { }; img.src = testImageURL; } + } }); const getImageUrl = inputFile => new Promise((resolve, reject) => { diff --git a/app/javascript/mastodon/actions/markers.ts b/app/javascript/mastodon/actions/markers.ts index 0b3280c2128dea..251546cb9a35b3 100644 --- a/app/javascript/mastodon/actions/markers.ts +++ b/app/javascript/mastodon/actions/markers.ts @@ -37,8 +37,7 @@ export const synchronouslySubmitMarkers = createAppAsyncThunk( }); return; - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - } else if ('navigator' && 'sendBeacon' in navigator) { + } else if ('sendBeacon' in navigator) { // Failing that, we can use sendBeacon, but we have to encode the data as // FormData for DoorKeeper to recognize the token. const formData = new FormData(); diff --git a/app/javascript/mastodon/actions/notification_groups.ts b/app/javascript/mastodon/actions/notification_groups.ts index b40b04f8ccfd69..a359913e614bb4 100644 --- a/app/javascript/mastodon/actions/notification_groups.ts +++ b/app/javascript/mastodon/actions/notification_groups.ts @@ -70,6 +70,10 @@ function dispatchAssociatedRecords( const supportedGroupedNotificationTypes = ['favourite', 'reblog']; +export function shouldGroupNotificationType(type: string) { + return supportedGroupedNotificationTypes.includes(type); +} + export const fetchNotifications = createDataLoadingThunk( 'notificationGroups/fetch', async (_params, { getState }) => diff --git a/app/javascript/mastodon/actions/streaming.js b/app/javascript/mastodon/actions/streaming.js index b6fc31fae855ac..30e643363a1c0d 100644 --- a/app/javascript/mastodon/actions/streaming.js +++ b/app/javascript/mastodon/actions/streaming.js @@ -106,12 +106,13 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti dispatch(processNewNotificationForGroups(notificationJSON)); break; } - case 'notifications_merged': + case 'notifications_merged': { const state = getState(); if (state.notifications.top || !state.notifications.mounted) dispatch(expandNotifications({ forceLoad: true, maxId: undefined })); dispatch(refreshStaleNotificationGroups()); break; + } case 'conversation': // @ts-expect-error dispatch(updateConversations(JSON.parse(data.payload))); diff --git a/app/javascript/mastodon/components/media_gallery.jsx b/app/javascript/mastodon/components/media_gallery.jsx index 84cb4e04dcb5db..e059978442a131 100644 --- a/app/javascript/mastodon/components/media_gallery.jsx +++ b/app/javascript/mastodon/components/media_gallery.jsx @@ -196,7 +196,7 @@ class Item extends PureComponent { {visible && thumbnail} - {badges && ( + {visible && badges && (
{badges}
@@ -336,14 +336,14 @@ class MediaGallery extends PureComponent { return (
+ {children} + {(!visible || uncached) && (
{spoilerButton}
)} - {children} - {(visible && !uncached) && (
diff --git a/app/javascript/mastodon/features/ui/components/column_link.jsx b/app/javascript/mastodon/features/ui/components/column_link.jsx index 3386c17f071f5e..f27ed50675a789 100644 --- a/app/javascript/mastodon/features/ui/components/column_link.jsx +++ b/app/javascript/mastodon/features/ui/components/column_link.jsx @@ -15,7 +15,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text if (href) { return ( - + {active ? activeIconElement : iconElement} {text} {badgeElement} @@ -23,7 +23,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text ); } else { return ( - + {active ? activeIconElement : iconElement} {text} {badgeElement} diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 18830708db615f..b11382cf0312b6 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -84,6 +84,7 @@ "alert.rate_limited.title": "معدل الطلبات محدود", "alert.unexpected.message": "لقد طرأ خطأ غير متوقّع.", "alert.unexpected.title": "المعذرة!", + "alt_text_badge.title": "نص بديل", "announcement.announcement": "إعلان", "attachments_list.unprocessed": "(غير معالَج)", "audio.hide": "إخفاء المقطع الصوتي", @@ -758,7 +759,7 @@ "status.history.edited": "عدله {name} {date}", "status.load_more": "حمّل المزيد", "status.media.open": "اضغط للفتح", - "status.media.show": "اضغط لإظهاره", + "status.media.show": "اضغط لإظهارها", "status.media_hidden": "وسائط مخفية", "status.mention": "أذكُر @{name}", "status.more": "المزيد", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index f2d0708882fae5..52dc6a49e2f2fe 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -85,6 +85,7 @@ "alert.rate_limited.title": "Cyfradd gyfyngedig", "alert.unexpected.message": "Digwyddodd gwall annisgwyl.", "alert.unexpected.title": "Wps!", + "alt_text_badge.title": "Testun Amgen", "announcement.announcement": "Cyhoeddiad", "attachments_list.unprocessed": "(heb eu prosesu)", "audio.hide": "Cuddio sain", @@ -221,6 +222,7 @@ "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 blocio.", "domain_block_modal.title": "Blocio parth?", + "domain_block_modal.you_will_lose_relationships": "Byddwch yn colli'r holl ddilynwyr a phobl rydych chi'n eu dilyn o'r gweinydd hwn.", "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.", @@ -849,6 +851,11 @@ "upload_error.poll": "Nid oes modd llwytho ffeiliau â phleidleisiau.", "upload_form.audio_description": "Disgrifio ar gyfer pobl sydd â cholled clyw", "upload_form.description": "Disgrifio i'r rheini a nam ar ei golwg", + "upload_form.drag_and_drop.instructions": "I godi atodiad cyfryngau, pwyswch y space neu enter. Wrth lusgo, defnyddiwch y bysellau saeth i symud yr atodiad cyfryngau i unrhyw gyfeiriad penodol. Pwyswch space neu enter eto i ollwng yr atodiad cyfryngau yn ei safle newydd, neu pwyswch escape i ddiddymu.", + "upload_form.drag_and_drop.on_drag_cancel": "Cafodd llusgo ei ddiddymu. Cafodd atodiad cyfryngau {item} ei ollwng.", + "upload_form.drag_and_drop.on_drag_end": "Cafodd atodiad cyfryngau {item} ei ollwng.", + "upload_form.drag_and_drop.on_drag_over": "Symudwyd atodiad cyfryngau {item}.", + "upload_form.drag_and_drop.on_drag_start": "Atodiad cyfryngau godwyd {item}.", "upload_form.edit": "Golygu", "upload_form.thumbnail": "Newid llun bach", "upload_form.video_description": "Disgrifio ar gyfer pobl sydd â cholled clyw neu amhariad golwg", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 6f45d4fe5329a3..0b541b2e4804f3 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -41,7 +41,7 @@ "account.go_to_profile": "Profil aufrufen", "account.hide_reblogs": "Geteilte Beiträge von @{name} ausblenden", "account.in_memoriam": "Zum Andenken.", - "account.joined_short": "Beigetreten", + "account.joined_short": "Mitglied seit", "account.languages": "Ausgewählte Sprachen ändern", "account.link_verified_on": "Das Profil mit dieser E-Mail-Adresse wurde bereits am {date} bestätigt", "account.locked_info": "Die Privatsphäre dieses Kontos wurde auf „geschützt“ gesetzt. Die Person bestimmt manuell, wer ihrem Profil folgen darf.", @@ -534,7 +534,7 @@ "notification.relationships_severance_event.domain_block": "Ein Admin von {from} hat {target} blockiert – darunter {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst.", "notification.relationships_severance_event.learn_more": "Mehr erfahren", "notification.relationships_severance_event.user_domain_block": "Du hast {target} blockiert – {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst, wurden entfernt.", - "notification.status": "{name} hat gerade etwas gepostet", + "notification.status": "{name} veröffentlichte gerade", "notification.update": "{name} bearbeitete einen Beitrag", "notification_requests.accept": "Genehmigen", "notification_requests.accept_multiple": "{count, plural, one {# Anfrage genehmigen …} other {# Anfragen genehmigen …}}", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 85f893c63ddc3e..2565f5da687011 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -85,6 +85,7 @@ "alert.rate_limited.title": "Περιορισμός συχνότητας", "alert.unexpected.message": "Προέκυψε απροσδόκητο σφάλμα.", "alert.unexpected.title": "Ουπς!", + "alt_text_badge.title": "Εναλλακτικό κείμενο", "announcement.announcement": "Ανακοίνωση", "attachments_list.unprocessed": "(μη επεξεργασμένο)", "audio.hide": "Απόκρυψη αρχείου ήχου", @@ -221,6 +222,8 @@ "domain_block_modal.they_cant_follow": "Κανείς από αυτόν τον διακομιστή δεν μπορεί να σε ακολουθήσει.", "domain_block_modal.they_wont_know": "Δεν θα ξέρουν ότι έχουν αποκλειστεί.", "domain_block_modal.title": "Αποκλεισμός τομέα;", + "domain_block_modal.you_will_lose_num_followers": "Θα χάσετε {followersCount, plural, one {{followersCountDisplay} ακόλουθο} other {{followersCountDisplay} ακόλουθους}} και {followingCount, plural, one {{followingCountDisplay} άτομο που ακολουθείτε} other {{followingCountDisplay} άτομα που ακολουθείτε}}.", + "domain_block_modal.you_will_lose_relationships": "Θα χάσετε όλους τους ακόλουθους και τα άτομα που ακολουθείτε από αυτόν τον διακομιστή.", "domain_block_modal.you_wont_see_posts": "Δεν θα βλέπεις αναρτήσεις ή ειδοποιήσεις από χρήστες σε αυτόν το διακομιστή.", "domain_pill.activitypub_lets_connect": "Σού επιτρέπει να συνδεθείς και να αλληλεπιδράσεις με τους ανθρώπους όχι μόνο στο Mastodon, αλλά και σε διαφορετικές κοινωνικές εφαρμογές.", "domain_pill.activitypub_like_language": "Το ActivityPub είναι σαν τη γλώσσα Mastodon μιλάει με άλλα κοινωνικά δίκτυα.", @@ -849,6 +852,11 @@ "upload_error.poll": "Στις δημοσκοπήσεις δεν επιτρέπεται η μεταφόρτωση αρχείου.", "upload_form.audio_description": "Περιγραφή για άτομα με προβλήματα ακοής", "upload_form.description": "Περιγραφή για άτομα με προβλήματα όρασης", + "upload_form.drag_and_drop.instructions": "Για να επιλέξετε ένα συνημμένο αρχείο πολυμέσων, πατήστε το Space ή το Enter. Ενώ το σέρνετε, χρησιμοποιήστε τα πλήκτρα βέλους για να μετακινήσετε το συνημμένο αρχείο πολυμέσων προς οποιαδήποτε κατεύθυνση. Πατήστε ξανά το Space ή το Enter για να αποθέσετε το συνημμένο αρχείο πολυμέσων στη νέα του θέση ή πατήστε το Escape για ακύρωση.", + "upload_form.drag_and_drop.on_drag_cancel": "Η μετακίνηση ακυρώθηκε. Έγινε απόθεση του συνημμένου αρχείου πολυμέσων «{item}».", + "upload_form.drag_and_drop.on_drag_end": "Έγινε απόθεση του συνημμένου αρχείου πολυμέσων «{item}».", + "upload_form.drag_and_drop.on_drag_over": "Έγινε μετακίνηση του συνημμένου αρχείου πολυμέσων «{item}».", + "upload_form.drag_and_drop.on_drag_start": "Έγινε επιλογή του συνημμένου αρχείου πολυμέσων «{item}».", "upload_form.edit": "Επεξεργασία", "upload_form.thumbnail": "Αλλαγή μικρογραφίας", "upload_form.video_description": "Περιγραφή για άτομα με προβλήματα ακοής ή όρασης", diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 1e78745359aa28..7f8dc74779824f 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -516,6 +516,7 @@ "notification.label.private_reply": "Private reply", "notification.label.reply": "Reply", "notification.mention": "Mention", + "notification.mentioned_you": "{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.", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 4268c385359327..35c2a5c7448e46 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -22,10 +22,10 @@ "account.cancel_follow_request": "Nuligi peton por sekvado", "account.copy": "Kopii ligilon al profilo", "account.direct": "Private mencii @{name}", - "account.disable_notifications": "Ne plu sciigi min, kiam @{name} mesaĝas", + "account.disable_notifications": "Ĉesu sciigi min kiam @{name} afiŝas", "account.domain_blocked": "Domajno blokita", "account.edit_profile": "Redakti la profilon", - "account.enable_notifications": "Sciigi min, kiam @{name} mesaĝas", + "account.enable_notifications": "Sciigu min kiam @{name} afiŝos", "account.endorse": "Rekomendi ĉe via profilo", "account.featured_tags.last_status_at": "Lasta afîŝo je {date}", "account.featured_tags.last_status_never": "Neniu afiŝo", @@ -49,14 +49,14 @@ "account.mention": "Mencii @{name}", "account.moved_to": "{name} indikis, ke ria nova konto estas nun:", "account.mute": "Silentigi @{name}", - "account.mute_notifications_short": "Silentigu Sciigojn", + "account.mute_notifications_short": "Silentigu sciigojn", "account.mute_short": "Silentigu", "account.muted": "Silentigita", "account.mutual": "Reciproka", "account.no_bio": "Neniu priskribo estas provizita.", "account.open_original_page": "Malfermi la originalan paĝon", "account.posts": "Afiŝoj", - "account.posts_with_replies": "Mesaĝoj kaj respondoj", + "account.posts_with_replies": "Afiŝoj kaj respondoj", "account.report": "Raporti @{name}", "account.requested": "Atendo de aprobo. Klaku por nuligi la peton por sekvado", "account.requested_follow": "{name} petis sekvi vin", @@ -69,7 +69,7 @@ "account.unendorse": "Ne plu rekomendi ĉe la profilo", "account.unfollow": "Ĉesi sekvi", "account.unmute": "Ne plu silentigi @{name}", - "account.unmute_notifications_short": "Malsilentigu Sciigojn", + "account.unmute_notifications_short": "Malsilentigu sciigojn", "account.unmute_short": "Ne plu silentigi", "account_note.placeholder": "Alklaku por aldoni noton", "admin.dashboard.daily_retention": "Uzantoretenprocento lau tag post registro", @@ -81,7 +81,7 @@ "admin.impact_report.instance_followers": "Sekvantojn niaj uzantoj perdus", "admin.impact_report.instance_follows": "Sekvantojn ties uzantoj perdus", "admin.impact_report.title": "Influa reporto", - "alert.rate_limited.message": "Bonvolu reprovi post {retry_time, time, medium}.", + "alert.rate_limited.message": "Bonvolu reprovi poste {retry_time, time, medium}.", "alert.rate_limited.title": "Mesaĝkvante limigita", "alert.unexpected.message": "Neatendita eraro okazis.", "alert.unexpected.title": "Aj!", @@ -163,7 +163,7 @@ "compose_form.poll.switch_to_single": "Ŝanĝi la balotenketon por permesi unu solan elekton", "compose_form.poll.type": "Stilo", "compose_form.publish": "Afiŝo", - "compose_form.publish_form": "Afiŝi", + "compose_form.publish_form": "Nova afiŝo", "compose_form.reply": "Respondi", "compose_form.save_changes": "Ĝisdatigi", "compose_form.spoiler.marked": "Forigi la averton de enhavo", @@ -173,7 +173,7 @@ "confirmations.block.confirm": "Bloki", "confirmations.delete.confirm": "Forigi", "confirmations.delete.message": "Ĉu vi certas, ke vi volas forigi ĉi tiun afiŝon?", - "confirmations.delete.title": "Ĉu forigi Afiŝon?", + "confirmations.delete.title": "Ĉu forigi afiŝon?", "confirmations.delete_list.confirm": "Forigi", "confirmations.delete_list.message": "Ĉu vi certas, ke vi volas porĉiame forigi ĉi tiun liston?", "confirmations.delete_list.title": "Ĉu forigi liston?", @@ -213,9 +213,9 @@ "dismissable_banner.community_timeline": "Jen la plej novaj publikaj afiŝoj de uzantoj, kies kontojn gastigas {domain}.", "dismissable_banner.dismiss": "Eksigi", "dismissable_banner.explore_links": "Tiuj novaĵoj estas aktuale priparolataj de uzantoj en tiu ĉi kaj aliaj serviloj, sur la malcentrigita reto.", - "dismissable_banner.explore_statuses": "Ĉi tioj estas afiŝoj de socia reto kiu populariĝas hodiau.", + "dismissable_banner.explore_statuses": "Ĉi tiuj estas afiŝoj de la tuta socia reto, kiuj populariĝas hodiaŭ. Pli novaj afiŝoj kun pli da diskonigoj kaj plej ŝatataj estas rangigitaj pli alte.", "dismissable_banner.explore_tags": "Ĉi tiuj kradvostoj populariĝas en ĉi tiu kaj aliaj serviloj en la malcentraliza reto nun.", - "dismissable_banner.public_timeline": "Ĉi tioj estas plej lastaj publikaj afiŝoj de personoj ĉe socia reto kiu personoj ĉe {domain} sekvas.", + "dismissable_banner.public_timeline": "Ĉi tiuj estas la plej lastatempaj publikaj afiŝoj de homoj en la socia reto, kiujn homoj sur {domain} sekvas.", "domain_block_modal.block": "Bloki servilon", "domain_block_modal.block_account_instead": "Bloki @{name} anstataŭe", "domain_block_modal.they_can_interact_with_old_posts": "Homoj de ĉi tiu servilo povas interagi kun viaj malnovaj afiŝoj.", @@ -265,8 +265,8 @@ "empty_column.direct": "Vi ankoraŭ ne havas privatan mencion. Kiam vi sendos aŭ ricevos iun, tiu aperos ĉi tie.", "empty_column.domain_blocks": "Ankoraŭ neniu domajno estas blokita.", "empty_column.explore_statuses": "Nenio tendencas nun. Rekontrolu poste!", - "empty_column.favourited_statuses": "Vi ankoraŭ ne havas stelumitan afiŝon.", - "empty_column.favourites": "Ankoraŭ neniu stelumis tiun afiŝon.", + "empty_column.favourited_statuses": "Vi ankoraŭ ne havas plej ŝatatajn afiŝojn. Kiam vi ŝatatas unu, ĝi aperos ĉi tie.", + "empty_column.favourites": "Neniu ankoraŭ ŝatis ĉi tiun afiŝon. Kiam iu ŝatos ĝin, ili aperos ĉi tie.", "empty_column.follow_requests": "Vi ne ankoraŭ havas iun peton de sekvado. Kiam vi ricevos unu, ĝi aperos ĉi tie.", "empty_column.followed_tags": "Vi ankoraŭ ne sekvas iujn kradvortojn. Kiam vi faras, ili aperos ĉi tie.", "empty_column.hashtag": "Ankoraŭ estas nenio per ĉi tiu kradvorto.", @@ -296,7 +296,7 @@ "filter_modal.added.review_and_configure": "Por kontroli kaj pli modifi ĉi tiu filtrilkategorio, iru al la {settings_link}.", "filter_modal.added.review_and_configure_title": "Filtrilopcioj", "filter_modal.added.settings_link": "opciopaĝo", - "filter_modal.added.short_explanation": "Ĉi tiu mesaĝo aldonitas al la filtrilkategorio: {title}.", + "filter_modal.added.short_explanation": "Ĉi tiu afiŝo aldonitas al la filtrilkategorio: {title}.", "filter_modal.added.title": "Filtrilo aldonita!", "filter_modal.select_filter.context_mismatch": "ne kongruas la kuntekston", "filter_modal.select_filter.expired": "eksvalidiĝinta", @@ -304,7 +304,7 @@ "filter_modal.select_filter.search": "Serĉi aŭ krei", "filter_modal.select_filter.subtitle": "Uzu ekzistantan kategorion aŭ kreu novan", "filter_modal.select_filter.title": "Filtri ĉi tiun afiŝon", - "filter_modal.title.status": "Filtri mesaĝon", + "filter_modal.title.status": "Filtri afiŝon", "filter_warning.matches_filter": "Filtrilo de kongruoj “{title}”", "filtered_notifications_banner.pending_requests": "El {count, plural, =0 {neniu} one {unu persono} other {# homoj}} vi eble konas", "filtered_notifications_banner.title": "Filtritaj sciigoj", @@ -351,7 +351,7 @@ "hashtag.column_settings.tag_toggle": "Aldoni pliajn etikedojn por ĉi tiu kolumno", "hashtag.counter_by_accounts": "{count, plural,one {{counter} partoprenanto} other {{counter} partoprenantoj}}", "hashtag.counter_by_uses": "{count, plural,one {{counter} afiŝo} other {{counter} afiŝoj}}", - "hashtag.counter_by_uses_today": "{count, plural,one {{counter} afiŝo} other {{counter} afiŝoj}} hodiau", + "hashtag.counter_by_uses_today": "{count, plural,one {{counter} afiŝo} other {{counter} afiŝoj}} hodiaŭ", "hashtag.follow": "Sekvi la kradvorton", "hashtag.unfollow": "Ne plu sekvi la kradvorton", "hashtags.and_other": "…kaj {count, plural,other {# pli}}", @@ -382,9 +382,9 @@ "ignore_notifications_modal.not_following_title": "Ĉu ignori sciigojn de homoj, kiujn vi ne sekvas?", "ignore_notifications_modal.private_mentions_title": "Ĉu ignori sciigojn de nepetitaj privataj mencioj?", "interaction_modal.description.favourite": "Per konto ĉe Mastodon, vi povas stelumiti ĉi tiun afiŝon por sciigi la afiŝanton ke vi aprezigas ŝin kaj konservas por la estonteco.", - "interaction_modal.description.follow": "Kun konto ĉe Mastodon, vi povos sekvi {name} por vidi ties mesaĝojn en via hejmo.", + "interaction_modal.description.follow": "Kun konto ĉe Mastodon, vi povas sekvi {name} por ricevi iliajn afiŝojn en via hejma fluo.", "interaction_modal.description.reblog": "Kun konto ĉe Mastodon, vi povas diskonigi ĉi tiun afiŝon, por ke viaj propraj sekvantoj vidu ĝin.", - "interaction_modal.description.reply": "Kun konto ĉe Mastodon, vi povos respondi al ĉi tiu mesaĝo.", + "interaction_modal.description.reply": "Kun konto ĉe Mastodon, vi povos respondi al ĉi tiu afiŝo.", "interaction_modal.login.action": "Prenu min hejmen", "interaction_modal.login.prompt": "Domajno de via hejma servilo, ekz. mastodon.social", "interaction_modal.no_account_yet": "Ĉu ne estas ĉe Mastodon?", @@ -402,12 +402,12 @@ "keyboard_shortcuts.back": "reveni", "keyboard_shortcuts.blocked": "Malfermi la liston de blokitaj uzantoj", "keyboard_shortcuts.boost": "Diskonigi la mesaĝon", - "keyboard_shortcuts.column": "fokusi mesaĝon en unu el la kolumnoj", + "keyboard_shortcuts.column": "Fokusi kolumnon", "keyboard_shortcuts.compose": "enfokusigi la tekstujon", "keyboard_shortcuts.description": "Priskribo", "keyboard_shortcuts.direct": "por malfermi la kolumnon pri privataj mencioj", "keyboard_shortcuts.down": "iri suben en la listo", - "keyboard_shortcuts.enter": "malfermi mesaĝon", + "keyboard_shortcuts.enter": "Malfermi afiŝon", "keyboard_shortcuts.favourite": "Stelumi afiŝon", "keyboard_shortcuts.favourites": "Malfermi la liston de la stelumoj", "keyboard_shortcuts.federated": "Malfermi la frataran templinion", @@ -421,16 +421,16 @@ "keyboard_shortcuts.my_profile": "malfermi vian profilon", "keyboard_shortcuts.notifications": "malfermi la kolumnon de sciigoj", "keyboard_shortcuts.open_media": "Malfermi plurmedion", - "keyboard_shortcuts.pinned": "malfermi la liston de alpinglitaj mesaĝoj", + "keyboard_shortcuts.pinned": "Malfermu alpinglitajn afiŝojn-liston", "keyboard_shortcuts.profile": "malfermi la profilon de la aŭtoro", - "keyboard_shortcuts.reply": "respondi", + "keyboard_shortcuts.reply": "Respondu al afiŝo", "keyboard_shortcuts.requests": "Malfermi la liston de petoj por sekvado", "keyboard_shortcuts.search": "enfokusigi la serĉilon", "keyboard_shortcuts.spoilers": "Montri/kaŝi la kampon de averto de enhavo (\"CW\")", "keyboard_shortcuts.start": "malfermi la kolumnon «por komenci»", "keyboard_shortcuts.toggle_hidden": "Montri/kaŝi tekston malantaŭ la averto de enhavo (\"CW\")", "keyboard_shortcuts.toggle_sensitivity": "Montri/kaŝi plurmedion", - "keyboard_shortcuts.toot": "Krei novan mesaĝon", + "keyboard_shortcuts.toot": "Komencu novan afiŝon", "keyboard_shortcuts.unfocus": "malenfokusigi la tekstujon aŭ la serĉilon", "keyboard_shortcuts.up": "iri supren en la listo", "lightbox.close": "Fermi", @@ -476,9 +476,9 @@ "navigation_bar.blocks": "Blokitaj uzantoj", "navigation_bar.bookmarks": "Legosignoj", "navigation_bar.community_timeline": "Loka templinio", - "navigation_bar.compose": "Skribi novan mesaĝon", + "navigation_bar.compose": "Redakti novan afiŝon", "navigation_bar.direct": "Privataj mencioj", - "navigation_bar.discover": "Esplori", + "navigation_bar.discover": "Malkovri", "navigation_bar.domain_blocks": "Blokitaj domajnoj", "navigation_bar.explore": "Esplori", "navigation_bar.favourites": "Stelumoj", @@ -487,12 +487,12 @@ "navigation_bar.followed_tags": "Sekvataj kradvortoj", "navigation_bar.follows_and_followers": "Sekvatoj kaj sekvantoj", "navigation_bar.lists": "Listoj", - "navigation_bar.logout": "Adiaŭi", + "navigation_bar.logout": "Elsaluti", "navigation_bar.moderation": "Modereco", "navigation_bar.mutes": "Silentigitaj uzantoj", "navigation_bar.opened_in_classic_interface": "Afiŝoj, kontoj, kaj aliaj specifaj paĝoj kiuj estas malfermititaj defaulta en la klasika reta interfaco.", "navigation_bar.personal": "Persone", - "navigation_bar.pins": "Alpinglitaj mesaĝoj", + "navigation_bar.pins": "Alpinglitaj afiŝoj", "navigation_bar.preferences": "Preferoj", "navigation_bar.public_timeline": "Fratara templinio", "navigation_bar.search": "Serĉi", @@ -572,7 +572,7 @@ "notifications.column_settings.reblog": "Diskonigoj:", "notifications.column_settings.show": "Montri en kolumno", "notifications.column_settings.sound": "Eligi sonon", - "notifications.column_settings.status": "Novaj mesaĝoj:", + "notifications.column_settings.status": "Novaj afiŝoj:", "notifications.column_settings.unread_notifications.category": "Nelegitaj sciigoj", "notifications.column_settings.unread_notifications.highlight": "Marki nelegitajn sciigojn", "notifications.column_settings.update": "Redaktoj:", @@ -660,7 +660,7 @@ "poll.votes": "{votes, plural, one {# voĉdono} other {# voĉdonoj}}", "poll_button.add_poll": "Aldoni balotenketon", "poll_button.remove_poll": "Forigi balotenketon", - "privacy.change": "Agordi mesaĝan privatecon", + "privacy.change": "Ŝanĝu afiŝan privatecon", "privacy.direct.long": "Ĉiuj menciitaj en la afiŝo", "privacy.direct.short": "Specifaj homoj", "privacy.private.long": "Nur viaj sekvantoj", @@ -775,13 +775,13 @@ "sign_in_banner.sso_redirect": "Ensalutu aŭ Registriĝi", "status.admin_account": "Malfermi fasadon de moderigado por @{name}", "status.admin_domain": "Malfermu moderigan interfacon por {domain}", - "status.admin_status": "Malfermi ĉi tiun mesaĝon en la kontrola interfaco", + "status.admin_status": "Malfermi ĉi tiun afiŝon en la kontrola interfaco", "status.block": "Bloki @{name}", "status.bookmark": "Aldoni al la legosignoj", "status.cancel_reblog_private": "Ne plu diskonigi", "status.cannot_reblog": "Ĉi tiun afiŝon ne eblas diskonigi", "status.continued_thread": "Daŭrigis fadenon", - "status.copy": "Kopii la ligilon al la mesaĝo", + "status.copy": "Kopii la ligilon al la afiŝo", "status.delete": "Forigi", "status.detailed_status": "Detala konversacia vido", "status.direct": "Private mencii @{name}", @@ -803,9 +803,9 @@ "status.more": "Pli", "status.mute": "Silentigi @{name}", "status.mute_conversation": "Silentigi konversacion", - "status.open": "Disvolvi la mesaĝon", + "status.open": "Pligrandigu ĉi tiun afiŝon", "status.pin": "Alpingli al la profilo", - "status.pinned": "Alpinglita mesaĝo", + "status.pinned": "Alpinglita afiŝo", "status.read_more": "Legi pli", "status.reblog": "Diskonigi", "status.reblog_private": "Diskonigi kun la sama videbleco", diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json index bdceb9bd30d036..3349be4fad1612 100644 --- a/app/javascript/mastodon/locales/fr-CA.json +++ b/app/javascript/mastodon/locales/fr-CA.json @@ -852,6 +852,7 @@ "upload_error.poll": "L’envoi de fichiers n’est pas autorisé avec les sondages.", "upload_form.audio_description": "Décrire pour les personnes ayant des difficultés d’audition", "upload_form.description": "Décrire pour les malvoyants", + "upload_form.drag_and_drop.instructions": "Pour choisir un média joint, appuyez sur la touche espace ou entrée. Tout en faisant glisser, utilisez les touches fléchées pour déplacer le fichier média dans une direction donnée. Appuyez à nouveau sur la touche espace ou entrée pour déposer le fichier média dans sa nouvelle position, ou appuyez sur la touche Echap pour annuler.", "upload_form.edit": "Modifier", "upload_form.thumbnail": "Changer la vignette", "upload_form.video_description": "Décrire pour les personnes ayant des problèmes de vue ou d'audition", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 2acad020935f04..5c4e582a87da4c 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -852,6 +852,7 @@ "upload_error.poll": "L’envoi de fichiers n’est pas autorisé avec les sondages.", "upload_form.audio_description": "Décrire pour les personnes ayant des difficultés d’audition", "upload_form.description": "Décrire pour les malvoyant·e·s", + "upload_form.drag_and_drop.instructions": "Pour choisir un média joint, appuyez sur la touche espace ou entrée. Tout en faisant glisser, utilisez les touches fléchées pour déplacer le fichier média dans une direction donnée. Appuyez à nouveau sur la touche espace ou entrée pour déposer le fichier média dans sa nouvelle position, ou appuyez sur la touche Echap pour annuler.", "upload_form.edit": "Modifier", "upload_form.thumbnail": "Changer la vignette", "upload_form.video_description": "Décrire pour les personnes ayant des problèmes de vue ou d'audition", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index ecbc11f3a2b7fa..f6d3f172ca1399 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -85,6 +85,7 @@ "alert.rate_limited.title": "Cuingeachadh ùine", "alert.unexpected.message": "Thachair mearachd ris nach robh dùil.", "alert.unexpected.title": "Oich!", + "alt_text_badge.title": "Roghainn teacsa", "announcement.announcement": "Brath-fios", "attachments_list.unprocessed": "(gun phròiseasadh)", "audio.hide": "Falaich an fhuaim", @@ -221,6 +222,8 @@ "domain_block_modal.they_cant_follow": "Chan urrainn do neach sam bith a th’ air an fhrithealaiche seo do leantainn.", "domain_block_modal.they_wont_know": "Cha bhi fios aca gun deach am bacadh.", "domain_block_modal.title": "A bheil thu airson an àrainn a bhacadh?", + "domain_block_modal.you_will_lose_num_followers": "Caillidh tu {followersCount, plural, one {{followersCountDisplay} neach-leantainn} two {{followersCountDisplay} luchd-leantainn} few {{followersCountDisplay} luchd-leantainn} other {{followersCountDisplay} luchd-leantainn}} ’s {followingCount, plural, one {{followingCountDisplay} neach a tha thu a’ leantainn} two {{followingCountDisplay} daoine a tha thu a’ leantainn} few {{followingCountDisplay} daoine a tha thu a’ leantainn} other {{followingCountDisplay} daoine a tha thu a’ leantainn}}.", + "domain_block_modal.you_will_lose_relationships": "Caillidh tu a h-uile luchd-leantainn ’s neach a leanas tu air an fhrithealaiche seo.", "domain_block_modal.you_wont_see_posts": "Chan fhaic thu postaichean no brathan o chleachdaichean a th’ air an fhrithealaiche seo.", "domain_pill.activitypub_lets_connect": "Leigidh e leat ceangal a dhèanamh ri daoine chan ann air Mastodon a-mhàin ach air feadh aplacaidean sòisealta eile cuideachd agus conaltradh leotha.", "domain_pill.activitypub_like_language": "Tha ActivityPub coltach ri cànan a bhruidhneas Mastodon ri lìonraidhean sòisealta eile.", @@ -330,7 +333,7 @@ "footer.about": "Mu dhèidhinn", "footer.directory": "Eòlaire nam pròifil", "footer.get_app": "Faigh an aplacaid", - "footer.invite": "Thoir cuireadh do dhaoine", + "footer.invite": "Thoir cuireadh", "footer.keyboard_shortcuts": "Ath-ghoiridean a’ mheur-chlàir", "footer.privacy_policy": "Poileasaidh prìobhaideachd", "footer.source_code": "Seall am bun-tùs", @@ -849,6 +852,11 @@ "upload_error.poll": "Chan fhaod thu faidhle a luchdadh suas an cois cunntais-bheachd.", "upload_form.audio_description": "Mìnich e dhan fheadhainn le èisteachd bheag", "upload_form.description": "Mìnich e dhan fheadhainn le cion-lèirsinne", + "upload_form.drag_and_drop.instructions": "Airson ceanglachan meadhain a thogail, brùth air space no enter. Fhad ’ a bhios tu ’ga shlaodadh, cleachd na h-iuchraichean-saighde airson an ceanglachan meadhain a ghluasad gu comhair sam bith. Brùth air space no enter a-rithist airson an ceanglachen meadhain a leigeil às air an ionad ùr aige no brùth air escape airson sgur dheth.", + "upload_form.drag_and_drop.on_drag_cancel": "Chaidh sgur dhen t-slaodadh. Chaidh an ceanglachan meadhain {item} a leigeil às.", + "upload_form.drag_and_drop.on_drag_end": "Chaidh an ceanglachan meadhain {item} a leigeil às.", + "upload_form.drag_and_drop.on_drag_over": "Chaidh an ceanglachan meadhain {item} a ghluasad.", + "upload_form.drag_and_drop.on_drag_start": "Chaidh an ceanglachan meadhain {item} a thogail.", "upload_form.edit": "Deasaich", "upload_form.thumbnail": "Atharraich an dealbhag", "upload_form.video_description": "Mìnich e dhan fheadhainn le èisteachd bheag no cion-lèirsinne", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 3bc9e1ee590dfd..2a31bfa4638d79 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -193,7 +193,7 @@ "confirmations.reply.message": "Ao responder sobrescribirás a mensaxe que estás a compor. Tes a certeza de que queres continuar?", "confirmations.reply.title": "Editar a publicación?", "confirmations.unfollow.confirm": "Deixar de seguir", - "confirmations.unfollow.message": "Desexas deixar de seguir a {name}?", + "confirmations.unfollow.message": "Tes certeza de querer deixar de seguir a {name}?", "confirmations.unfollow.title": "Deixar de seguir á usuaria?", "content_warning.hide": "Agochar publicación", "content_warning.show": "Mostrar igualmente", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 4ce0d41620d5dc..16f558e543e5a7 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -85,6 +85,7 @@ "alert.rate_limited.title": "חלה הגבלה על קצב התעבורה", "alert.unexpected.message": "אירעה שגיאה בלתי צפויה.", "alert.unexpected.title": "אופס!", + "alt_text_badge.title": "כיתוב חלופי", "announcement.announcement": "הכרזה", "attachments_list.unprocessed": "(לא מעובד)", "audio.hide": "השתק", @@ -221,6 +222,8 @@ "domain_block_modal.they_cant_follow": "משתמש משרת זה לא יכול לעקוב אחריך.", "domain_block_modal.they_wont_know": "הם לא ידעו כי נחסמו.", "domain_block_modal.title": "לחסום שרת?", + "domain_block_modal.you_will_lose_num_followers": "{followersCount, plural,one {יאבד לך עוקב אחד}other {יאבדו לך {followersCountDisplay} עוקבים}} {followingCount, plural,one {ונעקב אחד}other {ו־{followingCountDisplay} נעקבים}}.", + "domain_block_modal.you_will_lose_relationships": "יאבדו לך כל העוקבים והנעקבים משרת זה.", "domain_block_modal.you_wont_see_posts": "לא תוכלו לראות הודעות ממשתמשים על שרת זה.", "domain_pill.activitypub_lets_connect": "מאפשר לך להתחבר ולהתרועע עם אחרים לא רק במסטודון, אלא גם ביישומים חברתיים שונים אחרים.", "domain_pill.activitypub_like_language": "אקטיביטיפאב היא למעשה השפה בה מסטודון מדבר עם רשתות חברתיות אחרות.", @@ -849,6 +852,11 @@ "upload_error.poll": "לא ניתן להעלות קובץ עם סקר.", "upload_form.audio_description": "תאר/י עבור לקויי שמיעה", "upload_form.description": "תיאור לכבדי ראיה", + "upload_form.drag_and_drop.instructions": "כדי לבחור קובץ מוצמד, יש ללחוץ על מקש רווח או אנטר. בעת הגרירה, השתמשו במקשי החיצים כדי להזיז את הקובץ המוצמד בכל כיוון. לחצו רווח או אנטר בשנית כדי לעזוב את הקובץ במקומו החדש, או לחצו אסקייפ לביטול.", + "upload_form.drag_and_drop.on_drag_cancel": "הגרירה בוטלה. קובץ המדיה {item} נעזב.", + "upload_form.drag_and_drop.on_drag_end": "קובץ המדיה {item} נעזב.", + "upload_form.drag_and_drop.on_drag_over": "קובץ המדיה {item} הוזז.", + "upload_form.drag_and_drop.on_drag_start": "קובץ המדיה {item} נבחר.", "upload_form.edit": "עריכה", "upload_form.thumbnail": "שנה/י תמונה ממוזערת", "upload_form.video_description": "תאר/י עבור לקויי שמיעה ולקויי ראייה", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 34a9949afd1a1c..f9f403177c96dd 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -85,6 +85,7 @@ "alert.rate_limited.title": "Adatforgalom korlátozva", "alert.unexpected.message": "Váratlan hiba történt.", "alert.unexpected.title": "Hoppá!", + "alt_text_badge.title": "Helyettesítő szöveg", "announcement.announcement": "Közlemény", "attachments_list.unprocessed": "(feldolgozatlan)", "audio.hide": "Hang elrejtése", @@ -851,6 +852,11 @@ "upload_error.poll": "Szavazásnál nem lehet fájlt feltölteni.", "upload_form.audio_description": "Leírás siket vagy hallássérült emberek számára", "upload_form.description": "Leírás vak vagy gyengénlátó emberek számára", + "upload_form.drag_and_drop.instructions": "Egy médiamelléklet kiválasztásához nyomj Szóközt vagy Entert. Húzás közben használd a nyílgombokat a médiamelléklet adott irányba történő mozgatásához. A médiamelléklet új pozícióba helyezéséhez nyomd meg a Szóközt vagy az Entert, vagy a megszakításhoz nyomd meg az Esc gombot.", + "upload_form.drag_and_drop.on_drag_cancel": "Az áthúzás megszakítva. A(z) {item} médiamelléklet el lett dobva.", + "upload_form.drag_and_drop.on_drag_end": "A(z) {item} médiamelléklet el lett dobva.", + "upload_form.drag_and_drop.on_drag_over": "A(z) {item} médiamelléklet át lett helyezve.", + "upload_form.drag_and_drop.on_drag_start": "A(z) {item} médiamelléklet fel lett véve.", "upload_form.edit": "Szerkesztés", "upload_form.thumbnail": "Bélyegkép megváltoztatása", "upload_form.video_description": "Leírás siket, hallássérült, vak vagy gyengénlátó emberek számára", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index f5e7cc9c0484c3..46444863acea18 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -85,6 +85,7 @@ "alert.rate_limited.title": "制限に達しました", "alert.unexpected.message": "不明なエラーが発生しました。", "alert.unexpected.title": "エラー!", + "alt_text_badge.title": "代替テキスト", "announcement.announcement": "お知らせ", "attachments_list.unprocessed": "(未処理)", "audio.hide": "音声を閉じる", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 9e2c9f3af8079a..35e9be816e3a64 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -1,5 +1,5 @@ { - "about.blocks": "Ulac agbur", + "about.blocks": "Iqeddacen yettwaɛassen", "about.contact": "Anermis:", "about.disclaimer": "Mastodon d aseɣẓan ilelli, d aseɣẓan n uɣbalu yeldin, d tnezzut n Mastodon gGmbH.", "about.domain_blocks.no_reason_available": "Ulac taɣẓint", @@ -278,6 +278,8 @@ "hashtag.counter_by_uses_today": "{count, plural, one {{counter} n tsuffeɣt} other {{counter} n tsuffaɣ}} assa", "hashtag.follow": "Ḍfeṛ ahacṭag", "hashtags.and_other": "…d {count, plural, one {}other {# nniḍen}}", + "hints.threads.replies_may_be_missing": "Tiririyin d-yusan deg iqeddacen nniḍen, yezmer ur d-ddant ara.", + "hints.threads.see_more": "Wali ugar n tririt deg {domain}", "home.column_settings.show_reblogs": "Ssken-d beṭṭu", "home.column_settings.show_replies": "Ssken-d tiririyin", "home.hide_announcements": "Ffer ulɣuyen", @@ -550,6 +552,7 @@ "report_notification.attached_statuses": "{count, plural, one {{count} n tsuffeɣt} other {{count} n tsuffiɣin}} ttwaqnent", "report_notification.categories.legal": "Azerfan", "report_notification.categories.other": "Ayen nniḍen", + "report_notification.categories.other_sentence": "ayen nniḍen", "report_notification.categories.spam": "Aspam", "report_notification.categories.spam_sentence": "aspam", "report_notification.open": "Ldi aneqqis", @@ -584,11 +587,13 @@ "status.bookmark": "Creḍ", "status.cancel_reblog_private": "Sefsex beṭṭu", "status.cannot_reblog": "Tasuffeɣt-a ur tezmir ara ad tettwabḍu tikelt-nniḍen", + "status.continued_thread": "Asqerdec yettkemmil", "status.copy": "Nɣel assaɣ ɣer tasuffeɣt", "status.delete": "Kkes", "status.direct": "Bder-d @{name} weḥd-s", "status.direct_indicator": "Abdar uslig", "status.edit": "Ẓreg", + "status.edited": "Taẓrigt taneggarut {date}", "status.edited_x_times": "Tettwaẓreg {count, plural, one {{count} n tikkelt} other {{count} n tikkal}}", "status.embed": "Awi-d tangalt n weslaɣ", "status.favourite": "Amenyaf", @@ -614,9 +619,10 @@ "status.reblogs.empty": "Ula yiwen ur yebḍi tajewwiqt-agi ar tura. Ticki yebḍa-tt yiwen, ad d-iban da.", "status.redraft": "Kkes tɛiwdeḍ tira", "status.remove_bookmark": "Kkes tacreḍt", + "status.replied_in_thread": "Y·t·erra-d deg usqerdec", "status.replied_to": "Y·terra-yas i {name}", "status.reply": "Err", - "status.replyAll": "Err i lxiḍ", + "status.replyAll": "Err i wesqerdec", "status.report": "Cetki ɣef @{name}", "status.sensitive_warning": "Agbur amḥulfu", "status.share": "Bḍu", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 2054dfc0ff7ff1..e5e7dc2c17ff1e 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -317,7 +317,7 @@ "follow_suggestions.curated_suggestion": "스태프의 추천", "follow_suggestions.dismiss": "다시 보지 않기", "follow_suggestions.featured_longer": "{domain} 팀이 손수 고름", - "follow_suggestions.friends_of_friends_longer": "내가 팔로우 하는 사람들 사이에서 인기", + "follow_suggestions.friends_of_friends_longer": "내가 팔로우한 사람들 사이에서 인기", "follow_suggestions.hints.featured": "이 프로필은 {domain} 팀이 손수 선택했습니다.", "follow_suggestions.hints.friends_of_friends": "이 프로필은 내가 팔로우 하는 사람들에게서 유명합니다.", "follow_suggestions.hints.most_followed": "이 프로필은 {domain}에서 가장 많이 팔로우 된 사람들 중 하나입니다.", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 1c31574deaffe4..71523b37d8e73c 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -504,13 +504,13 @@ "notification.admin.report_statuses": "{name} rapporteerde {target} voor {category}", "notification.admin.report_statuses_other": "{name} rapporteerde {target}", "notification.admin.sign_up": "{name} heeft zich geregistreerd", - "notification.admin.sign_up.name_and_others": "{name} en {count, plural, one {# ander} other {# anderen}} hebben zich geregistreerd", + "notification.admin.sign_up.name_and_others": "{name} en {count, plural, one {# ander persoon} other {# andere personen}} hebben zich geregistreerd", "notification.favourite": "{name} markeerde jouw bericht als favoriet", - "notification.favourite.name_and_others_with_link": "{name} en {count, plural, one {# ander} other {# anderen}} hebben jouw bericht als favoriet gemarkeerd", + "notification.favourite.name_and_others_with_link": "{name} en {count, plural, one {# ander persoon} other {# andere personen}} hebben jouw bericht als favoriet gemarkeerd", "notification.follow": "{name} volgt jou nu", - "notification.follow.name_and_others": "{name} en {count, plural, one {# ander} other {# anderen}} hebben je gevolgd", + "notification.follow.name_and_others": "{name} en {count, plural, one {# ander persoon} other {# andere personen}} hebben je gevolgd", "notification.follow_request": "{name} wil jou graag volgen", - "notification.follow_request.name_and_others": "{name} en {count, plural, one {# ander} other {# anderen}} hebben gevraagd om je te volgen", + "notification.follow_request.name_and_others": "{name} en {count, plural, one {# ander persoon} other {# andere personen}} hebben gevraagd om je te volgen", "notification.label.mention": "Vermelding", "notification.label.private_mention": "Privébericht", "notification.label.private_reply": "Privéreactie", @@ -528,7 +528,7 @@ "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", - "notification.reblog.name_and_others_with_link": "{name} en {count, plural, one {# ander} other {# anderen}} hebben jouw bericht geboost", + "notification.reblog.name_and_others_with_link": "{name} en {count, plural, one {# ander persoon} other {# andere personen}} hebben jouw bericht geboost", "notification.relationships_severance_event": "Verloren verbindingen met {name}", "notification.relationships_severance_event.account_suspension": "Een beheerder van {from} heeft {target} geschorst, wat betekent dat je geen updates meer van hen kunt ontvangen of met hen kunt communiceren.", "notification.relationships_severance_event.domain_block": "Een beheerder van {from} heeft {target} geblokkeerd, inclusief {followersCount} van jouw volgers en {followingCount, plural, one {# account} other {# accounts}} die jij volgt.", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 8cd3387eaf968c..1dd5df32b8a4a5 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -502,6 +502,8 @@ "notification.reblog": "{name} fremhevet ditt innlegg", "notification.status": "{name} la nettopp ut", "notification.update": "{name} redigerte et innlegg", + "notification_requests.minimize_banner": "Minimer banneret for filtrerte varsler", + "notification_requests.view": "Vis varsler", "notifications.clear": "Fjern varsler", "notifications.clear_confirmation": "Er du sikker på at du vil fjerne alle dine varsler permanent?", "notifications.column_settings.admin.report": "Nye rapporter:", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index d1a3ecdaa73aff..ab5701cde0c0a7 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -437,6 +437,7 @@ "lightbox.next": "Próximo", "lightbox.previous": "Anterior", "lightbox.zoom_in": "Voltar para o tamanho real", + "lightbox.zoom_out": "Zoom para ajustar", "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}", @@ -813,7 +814,7 @@ "status.reblogs.empty": "Nada aqui. Quando alguém der boost, o usuário aparecerá aqui.", "status.redraft": "Excluir e rascunhar", "status.remove_bookmark": "Remover do Salvos", - "status.replied_in_thread": "Respondido na discussão", + "status.replied_in_thread": "Respondido na conversa", "status.replied_to": "Em resposta a {name}", "status.reply": "Responder", "status.replyAll": "Responder a conversa", @@ -851,6 +852,11 @@ "upload_error.poll": "Mídias não podem ser anexadas em toots com enquetes.", "upload_form.audio_description": "Descrever para deficientes auditivos", "upload_form.description": "Descrever para deficientes visuais", + "upload_form.drag_and_drop.instructions": "Para pegar um anexo de mídia, pressione espaço ou enter. Enquanto arrastar, use as setas do teclado para mover o anexo de mídia em qualquer direção. Pressione espaço ou insira novamente para soltar o anexo de mídia em sua nova posição, ou pressione escape para cancelar.", + "upload_form.drag_and_drop.on_drag_cancel": "O arrastamento foi cancelado. O anexo da mídia {item} foi descartado.", + "upload_form.drag_and_drop.on_drag_end": "O anexo {item} foi removido.", + "upload_form.drag_and_drop.on_drag_over": "O anexo de mídia {item} foi movido.", + "upload_form.drag_and_drop.on_drag_start": "Foi coletado o anexo de mídia {item}.", "upload_form.edit": "Editar", "upload_form.thumbnail": "Alterar miniatura", "upload_form.video_description": "Descrever para deficientes auditivos ou visuais", diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json index bb7d062b95e31b..227a7483a72ae4 100644 --- a/app/javascript/mastodon/locales/sc.json +++ b/app/javascript/mastodon/locales/sc.json @@ -85,6 +85,7 @@ "alert.rate_limited.title": "Màssimu de rechestas barigadu", "alert.unexpected.message": "Ddoe est istada una faddina.", "alert.unexpected.title": "Oh!", + "alt_text_badge.title": "Testu alternativu", "announcement.announcement": "Annùntziu", "attachments_list.unprocessed": "(non protzessadu)", "audio.hide": "Cua s'àudio", @@ -97,6 +98,8 @@ "block_modal.title": "Boles blocare s'utente?", "block_modal.you_wont_see_mentions": "No as a bìdere is publicatziones chi mèntovent custa persone.", "boost_modal.combo": "Podes incarcare {combo} pro brincare custu sa borta chi benit", + "boost_modal.reblog": "Boles potentziare sa publicatzione?", + "boost_modal.undo_reblog": "Boles tzessare de potentziare sa publicatzione?", "bundle_column_error.copy_stacktrace": "Còpia s'informe de faddina", "bundle_column_error.error.body": "Sa pàgina pedida non faghiat a dda renderizare. Diat pòdere èssere pro neghe de una faddina in su còdighe nostru, o de unu problema de cumpatibilidade de su navigadore.", "bundle_column_error.error.title": "Oh, no!", @@ -104,11 +107,15 @@ "bundle_column_error.network.title": "Faddina de connessione", "bundle_column_error.retry": "Torra·bi a proare", "bundle_column_error.return": "Torra a sa pàgina printzipale", + "bundle_column_error.routing.body": "Impossìbile agatare sa pàgina rechesta. Seguru chi s'URL in sa barra de indiritzos est curretu?", "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Serra", "bundle_modal_error.message": "Faddina in su carrigamentu de custu cumponente.", "bundle_modal_error.retry": "Torra·bi a proare", + "closed_registrations.other_server_instructions": "Dae chi Mastodon est detzentralizadu, podes creare unu contu in un'àteru serbidore e interagire cun custu.", + "closed_registrations_modal.description": "Sa creatzione de contos in {domain} no est possìbile in custu momentu, però tene in cunsideru chi non tenes bisòngiu de unu contu ispetzìficu in {domain} pro impreare Mastodon.", "closed_registrations_modal.find_another_server": "Agata un'àteru serbidore", + "closed_registrations_modal.title": "Su registru a Mastodon", "column.about": "Informatziones", "column.blocks": "Persones blocadas", "column.bookmarks": "Sinnalibros", @@ -142,6 +149,7 @@ "compose.published.open": "Aberi", "compose.saved.body": "Publicatzione sarvada.", "compose_form.direct_message_warning_learn_more": "Àteras informatziones", + "compose_form.encryption_warning": "Is publicatziones a Mastodon no sunt critografados a nodu terminale. Non cumpartzas informatziones delicadas in Mastodon.", "compose_form.hashtag_warning": "Custa publicatzione no at a èssere ammustrada in peruna eticheta, dae chi no est pùblica. Isceti is publicatziones pùblicas podent èssere chircadas cun etichetas.", "compose_form.lock_disclaimer": "Su contu tuo no est {locked}. Cale si siat persone ti podet sighire pro bìdere is messàgios tuos chi imbies a sa gente chi ti sighit.", "compose_form.lock_disclaimer.lock": "blocadu", @@ -171,15 +179,23 @@ "confirmations.discard_edit_media.confirm": "Iscarta", "confirmations.discard_edit_media.message": "Tenes modìficas non sarvadas a is descritziones o a is anteprimas de is cuntenutos, ddas boles iscartare su matessi?", "confirmations.edit.confirm": "Modìfica", + "confirmations.edit.message": "Modifichende immoe as a subrascrìere su messàgiu chi ses iscriende. Seguru chi boles sighire?", + "confirmations.edit.title": "Boles subraiscrìere sa publicatzione?", "confirmations.logout.confirm": "Essi·nche", "confirmations.logout.message": "Seguru chi boles essire?", + "confirmations.logout.title": "Boles serrare sa sessione?", "confirmations.mute.confirm": "A sa muda", "confirmations.redraft.confirm": "Cantzella e torra a fàghere", "confirmations.redraft.message": "Seguru chi boles cantzellare e torrare a fàghere custa publicatzione? As a pèrdere is preferidos e is cumpartziduras, e is rispostas a su messàgiu originale ant a abarrare òrfanas.", + "confirmations.redraft.title": "Boles cantzellare e torrare a iscrìere sa publicatzione?", "confirmations.reply.confirm": "Risponde", "confirmations.reply.message": "Rispondende immoe as a subrascrìere su messàgiu chi ses iscriende. Seguru chi boles sighire?", + "confirmations.reply.title": "Boles subraiscrìere sa publicatzione?", "confirmations.unfollow.confirm": "Non sigas prus", "confirmations.unfollow.message": "Seguru chi non boles sighire prus a {name}?", + "confirmations.unfollow.title": "Boles tzessare de sighire s'utente?", + "content_warning.hide": "Cua sa publicatzione", + "content_warning.show": "Ammustra·dda su pròpiu", "conversation.delete": "Cantzella arresonada", "conversation.mark_as_read": "Signala comente lèghidu", "conversation.open": "Ammustra arresonada", @@ -193,7 +209,10 @@ "directory.recently_active": "Cun atividade dae pagu", "disabled_account_banner.account_settings": "Cunfiguratziones de su contu", "disabled_account_banner.text": "Su contu tuo {disabledAccount} no est ativu.", + "dismissable_banner.community_timeline": "Custas sunt is publicatziones pùblicas prus reghentes dae gente cun contu in {domain}.", "dismissable_banner.dismiss": "Iscarta", + "dismissable_banner.explore_links": "Custas sunt is istòrias de noas prus cumpartzidas in sa rete oe. Is istòrias prus noas publicadas dae gente prus diversa ant a èssere priorizadas.", + "dismissable_banner.explore_statuses": "Custas sunt publicatziones dae sa rete detzentralizada chi sunt retzende atentzione oe. Is publicatziones prus noas cun prus cumpartziduras e preferèntzias ant a èssere priorizadas.", "domain_block_modal.block": "Bloca su serbidore", "domain_block_modal.block_account_instead": "Bloca imbetzes a @{name}", "domain_block_modal.they_can_interact_with_old_posts": "Is persones de custu serbidore podent ancora interagire cun is publicatziones betzas tuas.", @@ -207,6 +226,7 @@ "domain_pill.their_handle": "S'identificadore suo:", "domain_pill.their_server": "Sa domo digitale sua, in ue istant totu is publicatziones suas.", "domain_pill.username": "Nòmine de utente", + "domain_pill.whats_in_a_handle": "Ite est un'identificadore?", "domain_pill.your_handle": "S'identificadore tuo:", "domain_pill.your_server": "Sa domo digitale tua, in ue istant totu is publicatziones tuas. Custa non t'agradat? Tràmuda serbidore in cale si siat momentu e bati·ti fintzas in fatu is sighidores tuos.", "domain_pill.your_username": "S'identificadore ùnicu tuo in custu serbidore. Si podent agatare utentes cun su matessi nòmine de utente in àteros serbidores.", @@ -254,6 +274,7 @@ "explore.trending_links": "Noas", "explore.trending_statuses": "Publicatziones", "explore.trending_tags": "Etichetas", + "filter_modal.added.context_mismatch_title": "Su cuntestu non currispondet.", "filter_modal.added.expired_title": "Filtru iscadidu.", "filter_modal.added.review_and_configure_title": "Cunfiguratziones de filtru", "filter_modal.added.settings_link": "pàgina de cunfiguratzione", @@ -277,7 +298,13 @@ "follow_suggestions.featured_longer": "Seberadu a manu dae s'iscuadra de {domain}", "follow_suggestions.friends_of_friends_longer": "Populare intre persones chi sighis", "follow_suggestions.hints.featured": "Custu profilu est istadu seberadu a manu dae s'iscuadra {domain}.", + "follow_suggestions.personalized_suggestion": "Cussìgiu personalizadu", + "follow_suggestions.popular_suggestion": "Cussìgiu populare", + "follow_suggestions.popular_suggestion_longer": "Populare a {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Profilos sìmiles a is chi as sighidu de reghente", "follow_suggestions.view_all": "Ammustra totu", + "follow_suggestions.who_to_follow": "Chie sighire", + "followed_tags": "Etichetas sighidas", "footer.about": "Informatziones", "footer.directory": "Diretòriu de profilos", "footer.get_app": "Otene s'aplicatzione", @@ -302,6 +329,11 @@ "hashtag.counter_by_uses_today": "{count, plural, one {{counter} publicatzione} other {{counter} publicatziones}} oe", "hashtag.follow": "Sighi su hashtag", "hashtag.unfollow": "Non sigas prus s'eticheta", + "hashtags.and_other": "… e {count, plural, one {un'àteru} other {àteros #}}", + "hints.profiles.posts_may_be_missing": "Podet èssere chi ammanchent tzertas publicatziones de custu profilu.", + "hints.profiles.see_more_posts": "Bide prus publicatziones a {domain}", + "hints.threads.replies_may_be_missing": "Podet èssere chi ammanchent rispostas dae àteros serbidores.", + "hints.threads.see_more": "Bide prus rispostas a {domain}", "home.column_settings.show_reblogs": "Ammustra is cumpartziduras", "home.column_settings.show_replies": "Ammustra rispostas", "home.hide_announcements": "Cua annùntzios", @@ -309,7 +341,14 @@ "home.pending_critical_update.link": "Ammustra is atualizatziones", "home.pending_critical_update.title": "Atualizatzione de seguresa crìtica a disponimentu.", "home.show_announcements": "Ammustra annùntzios", + "ignore_notifications_modal.disclaimer": "Mastodon non podet informare is utentes chi as innioradu is notìficas issoro. Inniorare notìficas no at a evitare chi s'imbient is messàgios.", + "ignore_notifications_modal.filter_instead": "Opuru filtra", + "ignore_notifications_modal.filter_to_act_users": "As a pòdere ancora atzetare, refudare o sinnalare a utentes", + "ignore_notifications_modal.filter_to_avoid_confusion": "Filtrare agiudat a evitare possìbiles confusiones", "interaction_modal.description.reply": "Podes rispòndere a custa publicatzione cun unu contu de Mastodon.", + "interaction_modal.login.action": "Torra a sa pàgina printzipale", + "interaction_modal.login.prompt": "Su domìniu de su serbidore domèsticu tuo, pro esempru mastodon.social", + "interaction_modal.no_account_yet": "Non ses in Mastodon?", "interaction_modal.on_this_server": "In custu serbidore", "interaction_modal.title.follow": "Sighi a {name}", "interaction_modal.title.reply": "Risponde a sa publicatzione de {name}", @@ -353,11 +392,13 @@ "lightbox.next": "Imbeniente", "lightbox.previous": "Pretzedente", "limited_account_hint.title": "Custu profilu est istadu cuadu dae sa moderatzione de {domain}.", + "link_preview.shares": "{count, plural, one {{counter} publicatzione} other {{counter} publicatziones}}", "lists.account.add": "Agiunghe a sa lista", "lists.account.remove": "Boga dae sa lista", "lists.delete": "Cantzella sa lista", "lists.edit": "Modìfica sa lista", "lists.edit.submit": "Muda su tìtulu", + "lists.exclusive": "Cua custas publicatziones dae sa pàgina printzipale", "lists.new.create": "Agiunghe lista", "lists.new.title_placeholder": "Tìtulu de sa lista noa", "lists.replies_policy.followed": "Cale si siat persone chi sighis", @@ -368,7 +409,20 @@ "lists.subheading": "Is listas tuas", "load_pending": "{count, plural, one {# elementu nou} other {# elementos noos}}", "loading_indicator.label": "Carrighende…", + "media_gallery.hide": "Cua", + "moved_to_account_banner.text": "Su contu tuo {disabledAccount} est disativadu in custu momentu ca est istadu tramudadu a {movedToAccount}.", + "mute_modal.hide_from_notifications": "Cua dae is notìficas", + "mute_modal.hide_options": "Cua is optziones", + "mute_modal.indefinite": "Fintzas a cando no apo a torrare a ativare is notìficas", + "mute_modal.show_options": "Ammustra is optziones", + "mute_modal.they_can_mention_and_follow": "Ti podent mentovare e sighire, però no ddos as a bìdere.", + "mute_modal.they_wont_know": "No ant a ischire chi ddos as postu a sa muda.", + "mute_modal.title": "Boles pònnere a custu contu a sa muda?", + "mute_modal.you_wont_see_mentions": "No as a bìdere is publicatziones chi mèntovent a custa persone.", + "mute_modal.you_wont_see_posts": "At a pòdere bìdere is publicatziones tuas, però tue no as a bìdere cussas suas.", "navigation_bar.about": "Informatziones", + "navigation_bar.administration": "Amministratzione", + "navigation_bar.advanced_interface": "Aberi s'interfache web avantzada", "navigation_bar.blocks": "Persones blocadas", "navigation_bar.bookmarks": "Sinnalibros", "navigation_bar.community_timeline": "Lìnia de tempus locale", @@ -380,10 +434,13 @@ "navigation_bar.favourites": "Preferidos", "navigation_bar.filters": "Faeddos a sa muda", "navigation_bar.follow_requests": "Rechestas de sighidura", + "navigation_bar.followed_tags": "Etichetas sighidas", "navigation_bar.follows_and_followers": "Gente chi sighis e sighiduras", "navigation_bar.lists": "Listas", "navigation_bar.logout": "Essi", + "navigation_bar.moderation": "Moderatzione", "navigation_bar.mutes": "Persones a sa muda", + "navigation_bar.opened_in_classic_interface": "Publicatziones, contos e àteras pàginas ispetzìficas sunt abertas in manera predefinida in s'interfache web clàssica.", "navigation_bar.personal": "Informatziones personales", "navigation_bar.pins": "Publicatziones apicadas", "navigation_bar.preferences": "Preferèntzias", @@ -391,10 +448,24 @@ "navigation_bar.search": "Chirca", "navigation_bar.security": "Seguresa", "not_signed_in_indicator.not_signed_in": "Ti depes identificare pro atzèdere a custa resursa.", + "notification.admin.report": "{name} at sinnaladu a {target}", + "notification.admin.report_account": "{name} at sinnaladu {count, plural, one {una publicatzione} other {# publicatziones}} dae {target} pro {category}", + "notification.admin.report_account_other": "{name} at sinnaladu {count, plural, one {una publicatzione} other {# publicatziones}} dae {target}", + "notification.admin.report_statuses": "{name} at sinnaladu a {target} pro {category}", + "notification.admin.report_statuses_other": "{name} at sinnaladu a {target}", "notification.admin.sign_up": "{name} at aderidu", + "notification.admin.sign_up.name_and_others": "{name} e {count, plural, one {un'àtera persone} other {àteras # persones}} si sunt registradas", "notification.favourite": "{name} at marcadu comente a preferidu s'istadu tuo", + "notification.favourite.name_and_others_with_link": "{name} e {count, plural, one {un'àtera persone} other {àteras # persones}} ant marcadu sa publicatzione tua comente preferida", "notification.follow": "{name} ti sighit", + "notification.follow.name_and_others": "{name} e {count, plural, one {un'àtera persone} other {àteras # persones}} ti sighint", "notification.follow_request": "{name} at dimandadu de ti sighire", + "notification.follow_request.name_and_others": "{name} e {count, plural, one {un'àtera persone} other {àteras # persones}} ant pedidu de ti sighire", + "notification.label.mention": "Mèntovu", + "notification.label.private_mention": "Mèntovu privadu", + "notification.label.private_reply": "Risposta privada", + "notification.label.reply": "Risposta", + "notification.mention": "Mèntovu", "notification.moderation-warning.learn_more": "Àteras informatziones", "notification.moderation_warning": "T'ant imbiadu un'avisu de moderatzione", "notification.moderation_warning.action_delete_statuses": "Unas cantas de is publicatziones tuas sunt istadas cantzelladas.", @@ -407,12 +478,30 @@ "notification.own_poll": "Sondàgiu acabbadu", "notification.poll": "Unu sondàgiu in su chi as votadu est acabbadu", "notification.reblog": "{name} at cumpartzidu sa publicatzione tua", + "notification.reblog.name_and_others_with_link": "{name} e {count, plural, one {un'àtera persone} other {àteras # persones}} ant potentziadu sa publicatzione tua", "notification.relationships_severance_event": "Connessiones pèrdidas cun {name}", + "notification.relationships_severance_event.account_suspension": "S'amministratzione de {from} at suspèndidu a {target}; custu bolet nàrrere chi non podes prus retzire atualizatziones dae in cue o interagire cun cussos contos.", + "notification.relationships_severance_event.domain_block": "S'amministratzione de {from} at blocadu a {target}, incluende {followersCount} sighiduras tuas e {followingCount, plural, one {un'àteru contu} other {àteros # contos}} chi sighis.", "notification.relationships_severance_event.learn_more": "Àteras informatziones", + "notification.relationships_severance_event.user_domain_block": "As blocadu a {target}, bogadu a {followersCount} contos chi ti sighint e {followingCount, plural, one {un'àteru contu} other {àteros # contos}} chi sighis.", "notification.status": "{name} at publicadu cosa", "notification.update": "{name} at modificadu una publicatzione", "notification_requests.accept": "Atzeta", + "notification_requests.accept_multiple": "{count, plural, one {Atzeta una rechesta…} other {Atzeta # rechestas…}}", + "notification_requests.confirm_accept_multiple.button": "{count, plural, one {Atzeta sa rechesta} other {Atzeta is rechestas}}", + "notification_requests.confirm_accept_multiple.message": "Ses atzetende {count, plural, one {una rechesta de notìfica} other {# rechestas de notìfica}}. Seguru chi boles sighire?", + "notification_requests.confirm_accept_multiple.title": "Boles atzetare is rechestas de notìfica?", + "notification_requests.confirm_dismiss_multiple.button": "{count, plural, one {Iscarta sa rechesta} other {Iscarta is rechestas}}", + "notification_requests.confirm_dismiss_multiple.message": "Ses acanta de iscartare {count, plural, one {una rechesta de notìfica} other {# rechestas de notìfica}}. No nche {count, plural, one {} other {}} as a pòdere prus atzèdere in manera sèmplitze. Seguru chi boles sighire?", + "notification_requests.confirm_dismiss_multiple.title": "Boles iscartare is rechestas de notìfica?", "notification_requests.dismiss": "Iscarta", + "notification_requests.dismiss_multiple": "{count, plural, one {Iscarta una rechesta…} other {Iscarta # rechestas…}}", + "notification_requests.edit_selection": "Modifica", + "notification_requests.exit_selection": "Fatu", + "notification_requests.explainer_for_limited_account": "Is notìficas de custu contu sunt istadas filtradas, ca su contu est istadu limitadu dae sa moderatzione.", + "notification_requests.explainer_for_limited_remote_account": "Is notìficas de custu contu sunt istadas filtradas, ca su contu o su serbidore suo est istadu limitadu dae sa moderatzione.", + "notification_requests.maximize": "Ismànnia", + "notification_requests.minimize_banner": "Mìnima su bànner de notìficas filtradas", "notification_requests.notifications_from": "Notìficas dae {name}", "notification_requests.title": "Notìficas filtradas", "notifications.clear": "Lìmpia notìficas", @@ -472,6 +561,11 @@ "poll_button.add_poll": "Agiunghe unu sondàgiu", "poll_button.remove_poll": "Cantzella su sondàgiu", "privacy.change": "Modìfica s'istadu de riservadesa", + "privacy.direct.long": "Totu is utentes mentovados in sa publicatzione", + "privacy.direct.short": "Persones ispetzìficas", + "privacy.private.long": "Isceti chie ti sighit", + "privacy.private.short": "Sighiduras", + "privacy.public.long": "Cale si siat persone a intro o a foras de Mastodon", "privacy.public.short": "Pùblicu", "privacy_policy.last_updated": "Ùrtima atualizatzione: {date}", "privacy_policy.title": "Polìtica de riservadesa", @@ -497,34 +591,64 @@ "report.categories.legal": "Giurìdicu", "report.categories.other": "Àteru", "report.categories.spam": "Àliga", + "report.category.subtitle": "Sèbera sa currispondèntzia prus arta", + "report.category.title": "Nara·nos ite sutzedet cun custu {type}", "report.category.title_account": "profilu", "report.category.title_status": "publicatzione", "report.close": "Fatu", + "report.comment.title": "Nch'at àteru chi depamus ischire?", "report.forward": "Torra a imbiare a {target}", "report.forward_hint": "Custu contu est de un'àteru serbidore. Ddi boles imbiare puru una còpia anònima de custu informe?", "report.mute": "A sa muda", + "report.mute_explanation": "No as a bìdere is publicatziones suas. Ti podet ancora sighire e bìdere is publicatziones, ma no at a ischire chi dd'as postu a sa muda.", "report.next": "Imbeniente", "report.placeholder": "Cummentos additzionales", "report.reasons.dislike": "Non mi praghet", "report.reasons.dislike_description": "Est una cosa chi non boles bìdere", "report.reasons.legal": "Illegale", "report.reasons.other": "Un'àtera cosa", + "report.reasons.other_description": "Su problema non currispondet a is àteras categorias", "report.reasons.spam": "Est àliga", + "report.rules.subtitle": "Seletziona totu is chi àplichent", + "report.statuses.subtitle": "Seletziona totu is chi àplichent", "report.submit": "Imbia", "report.target": "Informende de {target}", + "report.thanks.title": "Non boles bìdere custu?", + "report.thanks.title_actionable": "Gràtzias de sa sinnalatzione, dd'amus a averiguare.", "report.unfollow": "Non sigas prus a @{name}", + "report.unfollow_explanation": "Ses sighende custu contu. Si non boles bìdere is publicatziones suas in sa pàgina printzipale tua, no ddu sigas prus.", "report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached", "report_notification.categories.legal": "Giurìdicu", "report_notification.categories.legal_sentence": "cuntenutu illegale", "report_notification.categories.other": "Àteru", "report_notification.categories.other_sentence": "àteru", "report_notification.categories.spam": "Àliga", + "report_notification.categories.spam_sentence": "àliga", + "report_notification.open": "Aberi una sinnalatzione", + "search.no_recent_searches": "Nissuna chirca reghente", "search.placeholder": "Chirca", + "search.quick_action.account_search": "Profilos chi currispondent cun {x}", + "search.quick_action.go_to_account": "Bae a su profilu {x}", + "search.quick_action.go_to_hashtag": "Bae a s'eticheta {x}", + "search.quick_action.open_url": "Aberi s'URL in Mastodon", + "search.quick_action.status_search": "Publicatziones chi currispondent cun {x}", + "search.search_or_paste": "Chirca o incolla un'URL", + "search_popout.full_text_search_disabled_message": "No a disponimentu a {domain}.", + "search_popout.full_text_search_logged_out_message": "Isceti a disponimentu cun sa sessione aberta.", + "search_popout.language_code": "Còdighe de limba ISO", + "search_popout.options": "Optziones de chirca", + "search_popout.quick_actions": "Atziones lestras", + "search_popout.recent": "Chircas reghentes", + "search_popout.specific_date": "data ispetzìfica", "search_popout.user": "utente", "search_results.accounts": "Profilos", "search_results.all": "Totus", "search_results.hashtags": "Etichetas", + "search_results.nothing_found": "Impossìbile agatare currispondèntzias pro custos tèrmines de chirca", + "search_results.see_all": "Bide totu", "search_results.statuses": "Publicatziones", + "search_results.title": "Chirca {q}", + "server_banner.about_active_users": "Gente chi at impreadu custu serbidore is ùrtimas 30 dies (Utentes cun Atividade a su Mese)", "server_banner.active_users": "utentes ativos", "server_banner.administered_by": "Amministradu dae:", "server_banner.server_stats": "Istatìsticas de su serbidore:", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index ddf341584c0d85..da3b1eaefd5b32 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -33,7 +33,7 @@ "account.follow": "Sledovať", "account.follow_back": "Sledovať späť", "account.followers": "Sledovatelia", - "account.followers.empty": "Tento účet ešte nikto nesleduje.", + "account.followers.empty": "Ešte nikto nesleduje tohto užívateľa.", "account.followers_counter": "{count, plural, one {{counter} sledujúci} other {{counter} sledujúci}}", "account.following": "Sledovaný účet", "account.following_counter": "{count, plural, one {{counter} sledovaných} other {{counter} sledovaných}}", @@ -85,6 +85,7 @@ "alert.rate_limited.title": "Priveľa žiadostí", "alert.unexpected.message": "Vyskytla sa nečakaná chyba.", "alert.unexpected.title": "Ups!", + "alt_text_badge.title": "Alternatívny popis", "announcement.announcement": "Oznámenie", "attachments_list.unprocessed": "(nespracované)", "audio.hide": "Skryť zvuk", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 084ac9945fae18..15101be4718b3f 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -852,6 +852,11 @@ "upload_error.poll": "Me pyetësorët s’lejohet ngarkim kartelash.", "upload_form.audio_description": "Përshkruajeni për persona me dëgjim të kufizuar", "upload_form.description": "Përshkruajeni për persona me probleme shikimi", + "upload_form.drag_and_drop.instructions": "Që të merrni një bashkëngjitje media, shtypni tastin Space ose Enter. Teksa bëhet tërheqje, përdorni tastet shigjetë për ta shpënë bashkëngjitjen media në cilëndo drejtori që doni. Shtypni sërish Space ose Enter që të lihet bashkëngjitja media në pozicionin e vet të ri, ose shtypni Esc, që të anulohet veprimi.", + "upload_form.drag_and_drop.on_drag_cancel": "Tërheqja u anulua. Bashkëngjitja media {item} u la.", + "upload_form.drag_and_drop.on_drag_end": "Bashkëngjitja media {item} u la.", + "upload_form.drag_and_drop.on_drag_over": "Bashkëngjitja media {item} u lëviz.", + "upload_form.drag_and_drop.on_drag_start": "U mor bashkëngjitja media {item}.", "upload_form.edit": "Përpunoni", "upload_form.thumbnail": "Ndryshoni miniaturën", "upload_form.video_description": "Përshkruajeni për persona me dëgjim të kufizuar ose probleme shikimi", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 6feae5d137d8ef..36c0b68f00c075 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -124,7 +124,7 @@ "column.direct": "Özel değinmeler", "column.directory": "Profillere göz at", "column.domain_blocks": "Engellenen alan adları", - "column.favourites": "Favorilerin", + "column.favourites": "Gözdelerin", "column.firehose": "Anlık Akışlar", "column.follow_requests": "Takip istekleri", "column.home": "Anasayfa", @@ -812,7 +812,7 @@ "status.reblogged_by": "{name} yeniden paylaştı", "status.reblogs": "{count, plural, one {yeniden paylaşım} other {yeniden paylaşım}}", "status.reblogs.empty": "Henüz hiç kimse bu gönderiyi yeniden paylaşmadı. Herhangi bir kullanıcı yeniden paylaştığında burada görüntülenecek.", - "status.redraft": "Sil,Düzenle ve Yeniden paylaş", + "status.redraft": "Sil,Düzenle ve yeniden-paylaş", "status.remove_bookmark": "Yer işaretini kaldır", "status.replied_in_thread": "Akışta yanıtlandı", "status.replied_to": "{name} kullanıcısına yanıt verdi", @@ -852,6 +852,11 @@ "upload_error.poll": "Anketlerde dosya yüklemesine izin verilmez.", "upload_form.audio_description": "İşitme kaybı olan kişiler için yazı ekleyiniz", "upload_form.description": "Görme engelliler için açıklama", + "upload_form.drag_and_drop.instructions": "Bir medya eklentisini taşımak için, boşluk veya enter tuşuna basın. Sürükleme sırasında medya eklentisini herhangi bir yöne hareket ettirmek için ok tuşlarını kullanın. Medya eklentisini yeni konumuna bırakmak için tekrar boşluk veya enter tuşuna basın veya işlemi iptal etmek için escape tuşuna basın.", + "upload_form.drag_and_drop.on_drag_cancel": "Sürükleme iptal edildi. Medya eklentisi {item} bırakıldı.", + "upload_form.drag_and_drop.on_drag_end": "Medya eklentisi {item} bırakıldı.", + "upload_form.drag_and_drop.on_drag_over": "Medya eklentisi {item} hareket ettirildi.", + "upload_form.drag_and_drop.on_drag_start": "Medya eklentisi {item} tutuldu.", "upload_form.edit": "Düzenle", "upload_form.thumbnail": "Küçük resmi değiştir", "upload_form.video_description": "İşitme kaybı veya görme engeli olan kişiler için açıklama ekleyiniz", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 1753d0bebe44df..a48b071f54f481 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -852,6 +852,11 @@ "upload_error.poll": "Не можна завантажувати файли до опитувань.", "upload_form.audio_description": "Опишіть для людей із вадами слуху", "upload_form.description": "Опишіть для людей з вадами зору", + "upload_form.drag_and_drop.instructions": "Щоб вибрати медіавкладення, натисніть пробіл або Enter. Під час перетягування, використайте клавіші зі стрілками для переміщення вкладення в будь-якому напрямку. Натисніть пробіл або Enter знову, щоб залишити медіавкладення в новому положенні, або натисніть клавішу Escape, щоб скасувати.", + "upload_form.drag_and_drop.on_drag_cancel": "Перетягування скасовано. Медіавкладення {item} прибрано.", + "upload_form.drag_and_drop.on_drag_end": "Медіавкладення {item} прибрано.", + "upload_form.drag_and_drop.on_drag_over": "Медіавкладення {item} переміщено.", + "upload_form.drag_and_drop.on_drag_start": "Медіавкладення {item} вибрано.", "upload_form.edit": "Змінити", "upload_form.thumbnail": "Змінити мініатюру", "upload_form.video_description": "Опишіть для людей із вадами слуху або зору", diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 9f66c09631d770..ba975b75a84f09 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -402,12 +402,12 @@ export default function compose(state = initialState, action) { .set('isUploadingThumbnail', false) .update('media_attachments', list => list.map(item => { if (item.get('id') === action.media.id) { - return fromJS(action.media); + return fromJS(action.media).set('unattached', item.get('unattached')); } return item; })); - case INIT_MEDIA_EDIT_MODAL: + case INIT_MEDIA_EDIT_MODAL: { const media = state.get('media_attachments').find(item => item.get('id') === action.id); return state.set('media_modal', ImmutableMap({ id: action.id, @@ -416,6 +416,7 @@ export default function compose(state = initialState, action) { focusY: media.getIn(['meta', 'focus', 'y'], 0), dirty: false, })); + } case COMPOSE_CHANGE_MEDIA_DESCRIPTION: return state.setIn(['media_modal', 'description'], action.description).setIn(['media_modal', 'dirty'], true); case COMPOSE_CHANGE_MEDIA_FOCUS: diff --git a/app/javascript/mastodon/reducers/notification_groups.ts b/app/javascript/mastodon/reducers/notification_groups.ts index f3c83ccd8d6e44..8b033f0fc78b7c 100644 --- a/app/javascript/mastodon/reducers/notification_groups.ts +++ b/app/javascript/mastodon/reducers/notification_groups.ts @@ -21,6 +21,7 @@ import { unmountNotifications, refreshStaleNotificationGroups, pollRecentNotifications, + shouldGroupNotificationType, } from 'mastodon/actions/notification_groups'; import { disconnectTimeline, @@ -205,6 +206,13 @@ function processNewNotification( groups: NotificationGroupsState['groups'], notification: ApiNotificationJSON, ) { + if (!shouldGroupNotificationType(notification.type)) { + notification = { + ...notification, + group_key: `ungrouped-${notification.id}`, + }; + } + const existingGroupIndex = groups.findIndex( (group) => group.type !== 'gap' && group.group_key === notification.group_key, @@ -242,7 +250,7 @@ function processNewNotification( groups.unshift(existingGroup); } } else { - // Create a new group + // We have not found an existing group, create a new one groups.unshift(createNotificationGroupFromNotificationJSON(notification)); } } diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js index 622f5e8e884bbd..c99a619b52dc69 100644 --- a/app/javascript/mastodon/reducers/notifications.js +++ b/app/javascript/mastodon/reducers/notifications.js @@ -298,9 +298,10 @@ export default function notifications(state = initialState, action) { return action.payload.timeline === 'home' ? state.update(action.payload.usePendingItems ? 'pendingItems' : 'items', items => items.first() ? items.unshift(null) : items) : state; - case NOTIFICATIONS_MARK_AS_READ: + case NOTIFICATIONS_MARK_AS_READ: { const lastNotification = state.get('items').find(item => item !== null); return lastNotification ? recountUnread(state, lastNotification.get('id')) : state; + } case NOTIFICATIONS_SET_BROWSER_SUPPORT: return state.set('browserSupport', action.value); case NOTIFICATIONS_SET_BROWSER_PERMISSION: diff --git a/app/javascript/mastodon/reducers/search.js b/app/javascript/mastodon/reducers/search.js index 7828d49eeedd9a..7de1c65c07a295 100644 --- a/app/javascript/mastodon/reducers/search.js +++ b/app/javascript/mastodon/reducers/search.js @@ -72,9 +72,10 @@ export default function search(state = initialState, action) { }); case SEARCH_EXPAND_REQUEST: return state.set('type', action.searchType).set('isLoading', true); - case SEARCH_EXPAND_SUCCESS: + case SEARCH_EXPAND_SUCCESS: { const results = action.searchType === 'hashtags' ? ImmutableOrderedSet(fromJS(action.results.hashtags)) : action.results[action.searchType].map(item => item.id); return state.updateIn(['results', action.searchType], list => list.union(results)).set('isLoading', false); + } case SEARCH_HISTORY_UPDATE: return state.set('recent', ImmutableOrderedSet(fromJS(action.recent))); default: diff --git a/app/javascript/mastodon/service_worker/web_push_locales.js b/app/javascript/mastodon/service_worker/web_push_locales.js index 89ae20007bba39..3e39c9a4edf890 100644 --- a/app/javascript/mastodon/service_worker/web_push_locales.js +++ b/app/javascript/mastodon/service_worker/web_push_locales.js @@ -6,6 +6,12 @@ const fs = require('fs'); const path = require('path'); +const { defineMessages } = require('react-intl'); + +const messages = defineMessages({ + mentioned_you: { id: 'notification.mentioned_you', defaultMessage: '{name} mentioned you' }, +}); + const filtered = {}; const filenames = fs.readdirSync(path.resolve(__dirname, '../locales')); @@ -20,7 +26,7 @@ filenames.forEach(filename => { 'notification.favourite': full['notification.favourite'] || '', 'notification.follow': full['notification.follow'] || '', 'notification.follow_request': full['notification.follow_request'] || '', - 'notification.mention': full['notification.mention'] || '', + 'notification.mention': full[messages.mentioned_you.id] || '', 'notification.reblog': full['notification.reblog'] || '', 'notification.poll': full['notification.poll'] || '', 'notification.status': full['notification.status'] || '', diff --git a/app/javascript/material-icons/400-24px/breaking_news-fill.svg b/app/javascript/material-icons/400-24px/breaking_news-fill.svg new file mode 100644 index 00000000000000..633ca48d57d6b4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/breaking_news-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/breaking_news.svg b/app/javascript/material-icons/400-24px/breaking_news.svg index d7dd0c12f47fec..c043f11a8b0207 100644 --- a/app/javascript/material-icons/400-24px/breaking_news.svg +++ b/app/javascript/material-icons/400-24px/breaking_news.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/captive_portal-fill.svg b/app/javascript/material-icons/400-24px/captive_portal-fill.svg new file mode 100644 index 00000000000000..5c0b26fb647b18 --- /dev/null +++ b/app/javascript/material-icons/400-24px/captive_portal-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/captive_portal.svg b/app/javascript/material-icons/400-24px/captive_portal.svg index 1f0f09c7734912..5c0b26fb647b18 100644 --- a/app/javascript/material-icons/400-24px/captive_portal.svg +++ b/app/javascript/material-icons/400-24px/captive_portal.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chat_bubble-fill.svg b/app/javascript/material-icons/400-24px/chat_bubble-fill.svg new file mode 100644 index 00000000000000..b47338a6c9c9ab --- /dev/null +++ b/app/javascript/material-icons/400-24px/chat_bubble-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chat_bubble.svg b/app/javascript/material-icons/400-24px/chat_bubble.svg index 7d210b460865ee..05d976d242d866 100644 --- a/app/javascript/material-icons/400-24px/chat_bubble.svg +++ b/app/javascript/material-icons/400-24px/chat_bubble.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud-fill.svg b/app/javascript/material-icons/400-24px/cloud-fill.svg new file mode 100644 index 00000000000000..d049a74c0191e3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/cloud-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud.svg b/app/javascript/material-icons/400-24px/cloud.svg index 75b4e957fc416a..a36bddda918e0f 100644 --- a/app/javascript/material-icons/400-24px/cloud.svg +++ b/app/javascript/material-icons/400-24px/cloud.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_download-fill.svg b/app/javascript/material-icons/400-24px/cloud_download-fill.svg new file mode 100644 index 00000000000000..c55d49f7e5c0dd --- /dev/null +++ b/app/javascript/material-icons/400-24px/cloud_download-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_download.svg b/app/javascript/material-icons/400-24px/cloud_download.svg index 2fc3717ff9e35e..8e9314800cca76 100644 --- a/app/javascript/material-icons/400-24px/cloud_download.svg +++ b/app/javascript/material-icons/400-24px/cloud_download.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_sync-fill.svg b/app/javascript/material-icons/400-24px/cloud_sync-fill.svg new file mode 100644 index 00000000000000..0c648e19e4f36b --- /dev/null +++ b/app/javascript/material-icons/400-24px/cloud_sync-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_sync.svg b/app/javascript/material-icons/400-24px/cloud_sync.svg index dbf6adc0001ada..461796e323ff9a 100644 --- a/app/javascript/material-icons/400-24px/cloud_sync.svg +++ b/app/javascript/material-icons/400-24px/cloud_sync.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_upload-fill.svg b/app/javascript/material-icons/400-24px/cloud_upload-fill.svg new file mode 100644 index 00000000000000..66a7bb22d3511e --- /dev/null +++ b/app/javascript/material-icons/400-24px/cloud_upload-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_upload.svg b/app/javascript/material-icons/400-24px/cloud_upload.svg index 5e1a4b9aef684f..94968cb94713bf 100644 --- a/app/javascript/material-icons/400-24px/cloud_upload.svg +++ b/app/javascript/material-icons/400-24px/cloud_upload.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/code.svg b/app/javascript/material-icons/400-24px/code.svg index 5bdc338f7f5bc6..8ef5c55cd48598 100644 --- a/app/javascript/material-icons/400-24px/code.svg +++ b/app/javascript/material-icons/400-24px/code.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/computer-fill.svg b/app/javascript/material-icons/400-24px/computer-fill.svg new file mode 100644 index 00000000000000..91295d68463510 --- /dev/null +++ b/app/javascript/material-icons/400-24px/computer-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/computer.svg b/app/javascript/material-icons/400-24px/computer.svg index 8c5bd9110e1d23..b8af5d46447944 100644 --- a/app/javascript/material-icons/400-24px/computer.svg +++ b/app/javascript/material-icons/400-24px/computer.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/contact_mail-fill.svg b/app/javascript/material-icons/400-24px/contact_mail-fill.svg new file mode 100644 index 00000000000000..c42c799955cc9a --- /dev/null +++ b/app/javascript/material-icons/400-24px/contact_mail-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/contact_mail.svg b/app/javascript/material-icons/400-24px/contact_mail.svg index 1ae26cc4d157ed..4547c48ec5b7b4 100644 --- a/app/javascript/material-icons/400-24px/contact_mail.svg +++ b/app/javascript/material-icons/400-24px/contact_mail.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/database-fill.svg b/app/javascript/material-icons/400-24px/database-fill.svg new file mode 100644 index 00000000000000..3520f6961446e6 --- /dev/null +++ b/app/javascript/material-icons/400-24px/database-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/database.svg b/app/javascript/material-icons/400-24px/database.svg index 54ca2f4e560b2e..a3bc2bfbc24474 100644 --- a/app/javascript/material-icons/400-24px/database.svg +++ b/app/javascript/material-icons/400-24px/database.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/diamond-fill.svg b/app/javascript/material-icons/400-24px/diamond-fill.svg new file mode 100644 index 00000000000000..474968ad6f8cdf --- /dev/null +++ b/app/javascript/material-icons/400-24px/diamond-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/diamond.svg b/app/javascript/material-icons/400-24px/diamond.svg index 26f4814b443b95..b604492fa8bf7c 100644 --- a/app/javascript/material-icons/400-24px/diamond.svg +++ b/app/javascript/material-icons/400-24px/diamond.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/filter_alt-fill.svg b/app/javascript/material-icons/400-24px/filter_alt-fill.svg new file mode 100644 index 00000000000000..ec1d90bba6bbd5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/filter_alt-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/filter_alt.svg b/app/javascript/material-icons/400-24px/filter_alt.svg index 0294cf1da53ac0..e4af9efd5d4d67 100644 --- a/app/javascript/material-icons/400-24px/filter_alt.svg +++ b/app/javascript/material-icons/400-24px/filter_alt.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/groups-fill.svg b/app/javascript/material-icons/400-24px/groups-fill.svg new file mode 100644 index 00000000000000..754eb0946c291c --- /dev/null +++ b/app/javascript/material-icons/400-24px/groups-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/groups.svg b/app/javascript/material-icons/400-24px/groups.svg index 0e795eb301d89d..998ff03729bd58 100644 --- a/app/javascript/material-icons/400-24px/groups.svg +++ b/app/javascript/material-icons/400-24px/groups.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/hide_source-fill.svg b/app/javascript/material-icons/400-24px/hide_source-fill.svg new file mode 100644 index 00000000000000..959631bc1aa150 --- /dev/null +++ b/app/javascript/material-icons/400-24px/hide_source-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/hide_source.svg b/app/javascript/material-icons/400-24px/hide_source.svg index d103ed770a5d6b..09633cef8c83b6 100644 --- a/app/javascript/material-icons/400-24px/hide_source.svg +++ b/app/javascript/material-icons/400-24px/hide_source.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/inbox-fill.svg b/app/javascript/material-icons/400-24px/inbox-fill.svg new file mode 100644 index 00000000000000..15ae2d8f3c4068 --- /dev/null +++ b/app/javascript/material-icons/400-24px/inbox-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/inbox.svg b/app/javascript/material-icons/400-24px/inbox.svg index 427817958c169a..32c727e8104990 100644 --- a/app/javascript/material-icons/400-24px/inbox.svg +++ b/app/javascript/material-icons/400-24px/inbox.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/list-fill.svg b/app/javascript/material-icons/400-24px/list-fill.svg new file mode 100644 index 00000000000000..c9cbe35eb52fa9 --- /dev/null +++ b/app/javascript/material-icons/400-24px/list-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/list.svg b/app/javascript/material-icons/400-24px/list.svg index 457a820ab1781b..c9cbe35eb52fa9 100644 --- a/app/javascript/material-icons/400-24px/list.svg +++ b/app/javascript/material-icons/400-24px/list.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/mail.svg b/app/javascript/material-icons/400-24px/mail.svg index a92ea7b198a82f..15e1d12d4e1a21 100644 --- a/app/javascript/material-icons/400-24px/mail.svg +++ b/app/javascript/material-icons/400-24px/mail.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/mood-fill.svg b/app/javascript/material-icons/400-24px/mood-fill.svg new file mode 100644 index 00000000000000..9480d0fb92aaa3 --- /dev/null +++ b/app/javascript/material-icons/400-24px/mood-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/mood.svg b/app/javascript/material-icons/400-24px/mood.svg index 27b3534244888c..46cafa76808008 100644 --- a/app/javascript/material-icons/400-24px/mood.svg +++ b/app/javascript/material-icons/400-24px/mood.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/report-fill.svg b/app/javascript/material-icons/400-24px/report-fill.svg new file mode 100644 index 00000000000000..50c638869d69cd --- /dev/null +++ b/app/javascript/material-icons/400-24px/report-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/report.svg b/app/javascript/material-icons/400-24px/report.svg index f281f0e1fa8f01..b08b5a1c987d5a 100644 --- a/app/javascript/material-icons/400-24px/report.svg +++ b/app/javascript/material-icons/400-24px/report.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/safety_check-fill.svg b/app/javascript/material-icons/400-24px/safety_check-fill.svg new file mode 100644 index 00000000000000..b38091a8ec4f2a --- /dev/null +++ b/app/javascript/material-icons/400-24px/safety_check-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/safety_check.svg b/app/javascript/material-icons/400-24px/safety_check.svg index f4eab46fb75b82..87bdba21fe3444 100644 --- a/app/javascript/material-icons/400-24px/safety_check.svg +++ b/app/javascript/material-icons/400-24px/safety_check.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/speed-fill.svg b/app/javascript/material-icons/400-24px/speed-fill.svg new file mode 100644 index 00000000000000..dca22ac521e3f0 --- /dev/null +++ b/app/javascript/material-icons/400-24px/speed-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/speed.svg b/app/javascript/material-icons/400-24px/speed.svg index ceb855c684f8c3..0837877f42f2f8 100644 --- a/app/javascript/material-icons/400-24px/speed.svg +++ b/app/javascript/material-icons/400-24px/speed.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/trending_up-fill.svg b/app/javascript/material-icons/400-24px/trending_up-fill.svg new file mode 100644 index 00000000000000..cd0e368964ec68 --- /dev/null +++ b/app/javascript/material-icons/400-24px/trending_up-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/trending_up.svg b/app/javascript/material-icons/400-24px/trending_up.svg index 06f9ba20639860..cd0e368964ec68 100644 --- a/app/javascript/material-icons/400-24px/trending_up.svg +++ b/app/javascript/material-icons/400-24px/trending_up.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 4d217cf5b7c357..062c7f1122293e 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -226,6 +226,10 @@ $content-width: 840px; gap: 5px; white-space: nowrap; + @media screen and (max-width: $mobile-breakpoint) { + flex: 1 0 50%; + } + &:hover, &:focus, &:active { @@ -1070,6 +1074,10 @@ a.name-tag, } } + .icon { + vertical-align: middle; + } + a.announcements-list__item__title { &:hover, &:focus, diff --git a/app/javascript/styles/mastodon/basics.scss b/app/javascript/styles/mastodon/basics.scss index 1f961cb9e1279d..1a74d8d52d3c24 100644 --- a/app/javascript/styles/mastodon/basics.scss +++ b/app/javascript/styles/mastodon/basics.scss @@ -141,6 +141,7 @@ body { width: 100%; height: auto; margin-top: -120px; + margin-bottom: -45px; } } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 498cfe96392bc8..801906d5c20548 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3611,6 +3611,7 @@ $ui-header-logo-wordmark-width: 99px; overflow-y: auto; width: 100%; height: 100%; + z-index: 0; } .drawer__inner__mastodon { diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss index af8ccf5b3839ef..0cbf5c1d554921 100644 --- a/app/javascript/styles/mastodon/tables.scss +++ b/app/javascript/styles/mastodon/tables.scss @@ -137,6 +137,7 @@ a.table-action-link { padding: 0 10px; color: $darker-text-color; font-weight: 500; + white-space: nowrap; &:hover { color: $highlight-text-color; diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 7f9429c5e4aa10..ce5cfb688c3b5e 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -42,6 +42,7 @@ def audience_cc def process_status @tags = [] @mentions = [] + @unresolved_mentions = [] @silenced_account_ids = [] @params = {} @@ -55,6 +56,7 @@ def process_status end resolve_thread(@status) + resolve_unresolved_mentions(@status) fetch_replies(@status) distribute forward_for_reply @@ -197,6 +199,8 @@ def process_mention(tag) return if account.nil? @mentions << Mention.new(account: account, silent: false) + rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError + @unresolved_mentions << tag['href'] end def process_emoji(tag) @@ -301,6 +305,12 @@ def resolve_thread(status) ThreadResolveWorker.perform_async(status.id, in_reply_to_uri, { 'request_id' => @options[:request_id] }) end + def resolve_unresolved_mentions(status) + @unresolved_mentions.uniq.each do |uri| + MentionResolveWorker.perform_in(rand(30...600).seconds, status.id, uri, { 'request_id' => @options[:request_id] }) + end + end + def fetch_replies(status) collection = @object['replies'] return if collection.blank? diff --git a/app/lib/vacuum/imports_vacuum.rb b/app/lib/vacuum/imports_vacuum.rb index 700bd81847f4ac..b67865194f39a9 100644 --- a/app/lib/vacuum/imports_vacuum.rb +++ b/app/lib/vacuum/imports_vacuum.rb @@ -9,10 +9,10 @@ def perform 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).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).in_batches.delete_all end end diff --git a/app/lib/web_push_request.rb b/app/lib/web_push_request.rb new file mode 100644 index 00000000000000..a43e22480e12a2 --- /dev/null +++ b/app/lib/web_push_request.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +class WebPushRequest + SIGNATURE_ALGORITHM = 'p256ecdsa' + AUTH_HEADER = 'WebPush' + PAYLOAD_EXPIRATION = 24.hours + JWT_ALGORITHM = 'ES256' + JWT_TYPE = 'JWT' + + attr_reader :web_push_subscription + + delegate( + :endpoint, + :key_auth, + :key_p256dh, + to: :web_push_subscription + ) + + def initialize(web_push_subscription) + @web_push_subscription = web_push_subscription + end + + def audience + @audience ||= Addressable::URI.parse(endpoint).normalized_site + end + + def authorization_header + [AUTH_HEADER, encoded_json_web_token].join(' ') + end + + def crypto_key_header + [SIGNATURE_ALGORITHM, vapid_key.public_key_for_push_header].join('=') + end + + def encrypt(payload) + Webpush::Encryption.encrypt(payload, key_p256dh, key_auth) + end + + private + + def encoded_json_web_token + JWT.encode( + web_token_payload, + vapid_key.curve, + JWT_ALGORITHM, + typ: JWT_TYPE + ) + end + + def web_token_payload + { + aud: audience, + exp: PAYLOAD_EXPIRATION.from_now.to_i, + sub: payload_subject, + } + end + + def payload_subject + [:mailto, contact_email].join(':') + end + + def vapid_key + @vapid_key ||= Webpush::VapidKey.from_keys( + Rails.configuration.x.vapid_public_key, + Rails.configuration.x.vapid_private_key + ) + end + + def contact_email + @contact_email ||= ::Setting.site_contact_email + end +end diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb index 4c374f5d57fde1..a20992dcb56f19 100644 --- a/app/mailers/notification_mailer.rb +++ b/app/mailers/notification_mailer.rb @@ -86,7 +86,7 @@ def set_list_headers! end def thread_by_conversation! - return if @status.conversation.nil? + return if @status&.conversation.nil? conversation_message_id = "" diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb index 42b1c49538b0a5..e2f359a8c32ef6 100644 --- a/app/models/account_filter.rb +++ b/app/models/account_filter.rb @@ -21,7 +21,7 @@ def initialize(params) end def results - scope = Account.includes(:account_stat, user: [:ips, :invite_request]).without_instance_actor.reorder(nil) + scope = Account.includes(:account_stat, user: [:ips, :invite_request]).without_instance_actor relevant_params.each do |key, value| next if key.to_s == 'page' diff --git a/app/models/admin/tag_filter.rb b/app/models/admin/tag_filter.rb index 6149c52175884b..5e75757b2374a7 100644 --- a/app/models/admin/tag_filter.rb +++ b/app/models/admin/tag_filter.rb @@ -14,7 +14,7 @@ def initialize(params) end def results - scope = Tag.reorder(nil) + scope = Tag.all params.each do |key, value| next if key == :page diff --git a/app/models/concerns/account/avatar.rb b/app/models/concerns/account/avatar.rb index 39f599db182275..5ca8fa862f9495 100644 --- a/app/models/concerns/account/avatar.rb +++ b/app/models/concerns/account/avatar.rb @@ -6,10 +6,13 @@ module Account::Avatar IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze LIMIT = 2.megabytes + AVATAR_DIMENSIONS = [400, 400].freeze + AVATAR_GEOMETRY = [AVATAR_DIMENSIONS.first, AVATAR_DIMENSIONS.last].join('x') + class_methods do def avatar_styles(file) - styles = { original: { geometry: '400x400#', file_geometry_parser: FastGeometryParser } } - styles[:static] = { geometry: '400x400#', format: 'png', convert_options: '-coalesce', file_geometry_parser: FastGeometryParser } if file.content_type == 'image/gif' + styles = { original: { geometry: "#{AVATAR_GEOMETRY}#", file_geometry_parser: FastGeometryParser } } + styles[:static] = { geometry: "#{AVATAR_GEOMETRY}#", format: 'png', convert_options: '-coalesce', file_geometry_parser: FastGeometryParser } if file.content_type == 'image/gif' styles end diff --git a/app/models/concerns/account/header.rb b/app/models/concerns/account/header.rb index 44ae774e94d034..2a47097fcfd038 100644 --- a/app/models/concerns/account/header.rb +++ b/app/models/concerns/account/header.rb @@ -5,7 +5,10 @@ module Account::Header IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze LIMIT = 2.megabytes - MAX_PIXELS = 750_000 # 1500x500px + + HEADER_DIMENSIONS = [1500, 500].freeze + HEADER_GEOMETRY = [HEADER_DIMENSIONS.first, HEADER_DIMENSIONS.last].join('x') + MAX_PIXELS = HEADER_DIMENSIONS.first * HEADER_DIMENSIONS.last class_methods do def header_styles(file) diff --git a/app/models/export.rb b/app/models/export.rb index 2457dcc1565ad4..6ed9f60c7c8cf4 100644 --- a/app/models/export.rb +++ b/app/models/export.rb @@ -55,42 +55,6 @@ def to_blocked_domains_csv end end - def total_storage - account.media_attachments.sum(:file_file_size) - end - - def total_statuses - account.statuses_count - end - - def total_bookmarks - account.bookmarks.count - end - - def total_follows - account.following_count - end - - def total_lists - account.owned_lists.count - end - - def total_followers - account.followers_count - end - - def total_blocks - account.blocking.count - end - - def total_mutes - account.muting.count - end - - def total_domain_blocks - account.domain_blocks.count - end - private def to_csv(accounts) diff --git a/app/models/remote_follow.rb b/app/models/remote_follow.rb index 10715ac97da425..fa0586f57eb4c9 100644 --- a/app/models/remote_follow.rb +++ b/app/models/remote_follow.rb @@ -3,7 +3,6 @@ class RemoteFollow include ActiveModel::Validations include RoutingHelper - include WebfingerHelper attr_accessor :acct, :addressable_template @@ -66,7 +65,7 @@ def redirect_uri_template end def acct_resource - @acct_resource ||= webfinger!("acct:#{acct}") + @acct_resource ||= Webfinger.new("acct:#{acct}").perform rescue Webfinger::Error, HTTP::ConnectionError nil end diff --git a/app/models/report_filter.rb b/app/models/report_filter.rb index fd0e23cb81705d..9d2b0fb37420f5 100644 --- a/app/models/report_filter.rb +++ b/app/models/report_filter.rb @@ -18,13 +18,25 @@ def initialize(params) def results scope = Report.unresolved - params.each do |key, value| + relevant_params.each do |key, value| scope = scope.merge scope_for(key, value) end scope end + private + + def relevant_params + params.tap do |args| + args.delete(:target_origin) if origin_is_remote_and_domain_present? + end + end + + def origin_is_remote_and_domain_present? + params[:target_origin] == 'remote' && params[:by_target_domain].present? + end + def scope_for(key, value) case key.to_sym when :by_target_domain diff --git a/app/models/session_activation.rb b/app/models/session_activation.rb index d0a77daf0a666c..8b8e533d30c980 100644 --- a/app/models/session_activation.rb +++ b/app/models/session_activation.rb @@ -28,6 +28,8 @@ class SessionActivation < ApplicationRecord before_create :assign_access_token + DEFAULT_SCOPES = %w(read write follow).freeze + class << self def active?(id) id && exists?(session_id: id) @@ -64,7 +66,7 @@ def access_token_attributes { application_id: Doorkeeper::Application.find_by(superapp: true)&.id, resource_owner_id: user_id, - scopes: 'read write follow', + scopes: DEFAULT_SCOPES.join(' '), expires_in: Doorkeeper.configuration.access_token_expires_in, use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?, } diff --git a/app/models/user.rb b/app/models/user.rb index df8444e2d3757b..e685ce65d32c06 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -71,7 +71,8 @@ class User < ApplicationRecord ACTIVE_DURATION = ENV.fetch('USER_ACTIVE_DAYS', 7).to_i.days.freeze devise :two_factor_authenticatable, - otp_secret_encryption_key: Rails.configuration.x.otp_secret + otp_secret_encryption_key: Rails.configuration.x.otp_secret, + otp_secret_length: 32 include LegacyOtpSecret # Must be after the above `devise` line in order to override the legacy method diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb index ddfd08146e76ae..9d30881bf38238 100644 --- a/app/models/web/push_subscription.rb +++ b/app/models/web/push_subscription.rb @@ -29,26 +29,6 @@ class Web::PushSubscription < ApplicationRecord delegate :locale, to: :associated_user - def encrypt(payload) - Webpush::Encryption.encrypt(payload, key_p256dh, key_auth) - end - - def audience - @audience ||= Addressable::URI.parse(endpoint).normalized_site - end - - def crypto_key_header - p256ecdsa = vapid_key.public_key_for_push_header - - "p256ecdsa=#{p256ecdsa}" - end - - def authorization_header - jwt = JWT.encode({ aud: audience, exp: 24.hours.from_now.to_i, sub: "mailto:#{contact_email}" }, vapid_key.curve, 'ES256', typ: 'JWT') - - "WebPush #{jwt}" - end - def pushable?(notification) policy_allows_notification?(notification) && alert_enabled_for_notification_type?(notification) end @@ -92,14 +72,6 @@ def find_or_create_access_token ) end - def vapid_key - @vapid_key ||= Webpush::VapidKey.from_keys(Rails.configuration.x.vapid_public_key, Rails.configuration.x.vapid_private_key) - end - - def contact_email - @contact_email ||= ::Setting.site_contact_email - end - def alert_enabled_for_notification_type?(notification) truthy?(data&.dig('alerts', notification.type.to_s)) end diff --git a/app/presenters/export_summary.rb b/app/presenters/export_summary.rb new file mode 100644 index 00000000000000..8e45aadf67dd49 --- /dev/null +++ b/app/presenters/export_summary.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +class ExportSummary + attr_reader :account, :counts + + delegate( + :blocking, + :bookmarks, + :domain_blocks, + :owned_lists, + :media_attachments, + :muting, + to: :account, + prefix: true + ) + + def initialize(account) + @account = account + @counts = populate_counts + end + + def total_blocks + counts[:blocks].value + end + + def total_bookmarks + counts[:bookmarks].value + end + + def total_domain_blocks + counts[:domain_blocks].value + end + + def total_followers + account.followers_count + end + + def total_follows + account.following_count + end + + def total_lists + counts[:owned_lists].value + end + + def total_mutes + counts[:muting].value + end + + def total_statuses + account.statuses_count + end + + def total_storage + counts[:storage].value + end + + private + + def populate_counts + { + blocks: account_blocking.async_count, + bookmarks: account_bookmarks.async_count, + domain_blocks: account_domain_blocks.async_count, + owned_lists: account_owned_lists.async_count, + muting: account_muting.async_count, + storage: account_media_attachments.async_sum(:file_file_size), + } + end +end diff --git a/app/services/activitypub/fetch_remote_actor_service.rb b/app/services/activitypub/fetch_remote_actor_service.rb index 2c372c2ec3fd84..560cf424e1539f 100644 --- a/app/services/activitypub/fetch_remote_actor_service.rb +++ b/app/services/activitypub/fetch_remote_actor_service.rb @@ -3,7 +3,6 @@ class ActivityPub::FetchRemoteActorService < BaseService include JsonLdHelper include DomainControlHelper - include WebfingerHelper class Error < StandardError; end @@ -45,7 +44,7 @@ def call(uri, prefetched_body: nil, break_on_redirect: false, only_key: false, s private def check_webfinger! - webfinger = webfinger!("acct:#{@username}@#{@domain}") + webfinger = Webfinger.new("acct:#{@username}@#{@domain}").perform confirmed_username, confirmed_domain = split_acct(webfinger.subject) if @username.casecmp(confirmed_username).zero? && @domain.casecmp(confirmed_domain).zero? @@ -54,7 +53,7 @@ def check_webfinger! return end - webfinger = webfinger!("acct:#{confirmed_username}@#{confirmed_domain}") + webfinger = Webfinger.new("acct:#{confirmed_username}@#{confirmed_domain}").perform @username, @domain = split_acct(webfinger.subject) raise Webfinger::RedirectError, "Too many webfinger redirects for URI #{@uri} (stopped at #{@username}@#{@domain})" unless confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero? diff --git a/app/services/activitypub/process_collection_service.rb b/app/services/activitypub/process_collection_service.rb index 4f049a5ae940b0..cadc7d2d10e300 100644 --- a/app/services/activitypub/process_collection_service.rb +++ b/app/services/activitypub/process_collection_service.rb @@ -2,6 +2,7 @@ class ActivityPub::ProcessCollectionService < BaseService include JsonLdHelper + include DomainControlHelper def call(body, actor, **options) @account = actor @@ -69,6 +70,9 @@ def process_item(item) end def verify_account! + return unless @json['signature'].is_a?(Hash) + return if domain_not_allowed?(@json['signature']['creator']) + @options[:relayed_through_actor] = @account @account = ActivityPub::LinkedDataSignature.new(@json).verify_actor! @account = nil unless @account.is_a?(Account) diff --git a/app/services/purge_domain_service.rb b/app/services/purge_domain_service.rb index ca0f0d441fe5bb..feab8aa1dd5da2 100644 --- a/app/services/purge_domain_service.rb +++ b/app/services/purge_domain_service.rb @@ -16,12 +16,12 @@ def purge_relationship_severance_events! end def purge_accounts! - Account.remote.where(domain: @domain).reorder(nil).find_each do |account| + Account.remote.where(domain: @domain).find_each do |account| DeleteAccountService.new.call(account, reserve_username: false, skip_side_effects: true) end end def purge_emojis! - CustomEmoji.remote.where(domain: @domain).reorder(nil).find_each(&:destroy) + CustomEmoji.remote.where(domain: @domain).find_each(&:destroy) end end diff --git a/app/services/resolve_account_service.rb b/app/services/resolve_account_service.rb index 8a5863baba6c7f..cd96b55c740e23 100644 --- a/app/services/resolve_account_service.rb +++ b/app/services/resolve_account_service.rb @@ -2,7 +2,6 @@ class ResolveAccountService < BaseService include DomainControlHelper - include WebfingerHelper include Redisable include Lockable @@ -81,7 +80,7 @@ def process_options!(uri, options) end def process_webfinger!(uri) - @webfinger = webfinger!("acct:#{uri}") + @webfinger = Webfinger.new("acct:#{uri}").perform confirmed_username, confirmed_domain = split_acct(@webfinger.subject) if confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero? @@ -91,7 +90,7 @@ def process_webfinger!(uri) end # Account doesn't match, so it may have been redirected - @webfinger = webfinger!("acct:#{confirmed_username}@#{confirmed_domain}") + @webfinger = Webfinger.new("acct:#{confirmed_username}@#{confirmed_domain}").perform @username, @domain = split_acct(@webfinger.subject) raise Webfinger::RedirectError, "Too many webfinger redirects for URI #{uri} (stopped at #{@username}@#{@domain})" unless confirmed_username.casecmp(@username).zero? && confirmed_domain.casecmp(@domain).zero? diff --git a/app/views/admin/action_logs/index.html.haml b/app/views/admin/action_logs/index.html.haml index c02c8f0ad41fae..a5d41882943cf2 100644 --- a/app/views/admin/action_logs/index.html.haml +++ b/app/views/admin/action_logs/index.html.haml @@ -16,7 +16,7 @@ %strong= t('admin.action_logs.filter_by_action') .input.select.optional = form.select :action_type, - options_for_select(Admin::ActionLogFilter::ACTION_TYPE_MAP.keys.map { |key| [I18n.t("admin.action_logs.action_types.#{key}"), key] }, params[:action_type]), + options_for_select(sorted_action_log_types, params[:action_type]), prompt: I18n.t('admin.accounts.moderation.all') - if @action_logs.empty? diff --git a/app/views/admin/announcements/index.html.haml b/app/views/admin/announcements/index.html.haml index 72227b04577a04..6a76c187766a5c 100644 --- a/app/views/admin/announcements/index.html.haml +++ b/app/views/admin/announcements/index.html.haml @@ -9,7 +9,7 @@ %strong= t('admin.relays.status') %ul %li= filter_link_to t('generic.all'), published: nil, unpublished: nil - %li= filter_link_to safe_join([t('admin.announcements.live'), "(#{number_with_delimiter(Announcement.published.count)})"], ' '), published: '1', unpublished: nil + %li= filter_link_to safe_join([t('admin.announcements.live'), "(#{number_with_delimiter(@published_announcements_count.value)})"], ' '), published: '1', unpublished: nil - if @announcements.empty? .muted-hint.center-text diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 27d8f4790ba8be..2b4d02fa67c0a0 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -2,9 +2,7 @@ = t('admin.dashboard.title') - content_for :heading_actions do - = l(@time_period.first) - = ' - ' - = l(@time_period.last) + = date_range(@time_period) - unless @system_checks.empty? .flash-message-stack diff --git a/app/views/admin/disputes/appeals/index.html.haml b/app/views/admin/disputes/appeals/index.html.haml index 7f04dd40fb5f91..e09e275e5d5c3e 100644 --- a/app/views/admin/disputes/appeals/index.html.haml +++ b/app/views/admin/disputes/appeals/index.html.haml @@ -5,7 +5,7 @@ .filter-subset %strong= t('admin.tags.review') %ul - %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Appeal.pending.count})"], ' '), status: 'pending' + %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{@pending_appeals_count.value})"], ' '), status: 'pending' %li= filter_link_to t('admin.trends.approved'), status: 'approved' %li= filter_link_to t('admin.trends.rejected'), status: 'rejected' diff --git a/app/views/admin/email_domain_blocks/new.html.haml b/app/views/admin/email_domain_blocks/new.html.haml index dd4b83ee3f2832..2dfdca93763dda 100644 --- a/app/views/admin/email_domain_blocks/new.html.haml +++ b/app/views/admin/email_domain_blocks/new.html.haml @@ -16,7 +16,7 @@ label: I18n.t('admin.email_domain_blocks.allow_registrations_with_approval'), wrapper: :with_label - - if defined?(@resolved_records) + - if defined?(@resolved_records) && @resolved_records.any? %p.hint= t('admin.email_domain_blocks.resolved_dns_records_hint_html') .batch-table diff --git a/app/views/admin/instances/_dashboard.html.haml b/app/views/admin/instances/_dashboard.html.haml new file mode 100644 index 00000000000000..ef8500103be462 --- /dev/null +++ b/app/views/admin/instances/_dashboard.html.haml @@ -0,0 +1,66 @@ +-# locals: (instance_domain:, period_end_at:, period_start_at:) +%p + = material_symbol 'info' + = t('admin.instances.totals_time_period_hint_html') + +.dashboard + .dashboard__item + = react_admin_component :counter, + end_at: period_end_at, + href: admin_accounts_path(origin: 'remote', by_domain: instance_domain), + label: t('admin.instances.dashboard.instance_accounts_measure'), + measure: 'instance_accounts', + params: { domain: instance_domain }, + start_at: period_start_at + .dashboard__item + = react_admin_component :counter, + end_at: period_end_at, + label: t('admin.instances.dashboard.instance_statuses_measure'), + measure: 'instance_statuses', + params: { domain: instance_domain }, + start_at: period_start_at + .dashboard__item + = react_admin_component :counter, + end_at: period_end_at, + label: t('admin.instances.dashboard.instance_media_attachments_measure'), + measure: 'instance_media_attachments', + params: { domain: instance_domain }, + start_at: period_start_at + .dashboard__item + = react_admin_component :counter, + end_at: period_end_at, + label: t('admin.instances.dashboard.instance_follows_measure'), + measure: 'instance_follows', + params: { domain: instance_domain }, + start_at: period_start_at + .dashboard__item + = react_admin_component :counter, + end_at: period_end_at, + label: t('admin.instances.dashboard.instance_followers_measure'), + measure: 'instance_followers', + params: { domain: instance_domain }, + start_at: period_start_at + .dashboard__item + = react_admin_component :counter, + end_at: period_end_at, + href: admin_reports_path(by_target_domain: instance_domain), + label: t('admin.instances.dashboard.instance_reports_measure'), + measure: 'instance_reports', + params: { domain: instance_domain }, + start_at: period_start_at + .dashboard__item + = react_admin_component :dimension, + dimension: 'instance_accounts', + end_at: period_end_at, + label: t('admin.instances.dashboard.instance_accounts_dimension'), + limit: 8, + params: { domain: instance_domain }, + start_at: period_start_at + .dashboard__item + = react_admin_component :dimension, + dimension: 'instance_languages', + end_at: period_end_at, + label: t('admin.instances.dashboard.instance_languages_dimension'), + limit: 8, + params: { domain: instance_domain }, + start_at: period_start_at diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml index c55eb89dc94933..812a9c8870b0eb 100644 --- a/app/views/admin/instances/show.html.haml +++ b/app/views/admin/instances/show.html.haml @@ -3,77 +3,10 @@ - if current_user.can?(:view_dashboard) - content_for :heading_actions do - = l(@time_period.first) - = ' - ' - = l(@time_period.last) + = date_range(@time_period) - if @instance.persisted? - %p - = material_symbol 'info' - = t('admin.instances.totals_time_period_hint_html') - - .dashboard - .dashboard__item - = react_admin_component :counter, - end_at: @time_period.last, - href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain), - label: t('admin.instances.dashboard.instance_accounts_measure'), - measure: 'instance_accounts', - params: { domain: @instance.domain }, - start_at: @time_period.first - .dashboard__item - = react_admin_component :counter, - end_at: @time_period.last, - label: t('admin.instances.dashboard.instance_statuses_measure'), - measure: 'instance_statuses', - params: { domain: @instance.domain }, - start_at: @time_period.first - .dashboard__item - = react_admin_component :counter, - end_at: @time_period.last, - label: t('admin.instances.dashboard.instance_media_attachments_measure'), - measure: 'instance_media_attachments', - params: { domain: @instance.domain }, - start_at: @time_period.first - .dashboard__item - = react_admin_component :counter, - end_at: @time_period.last, - label: t('admin.instances.dashboard.instance_follows_measure'), - measure: 'instance_follows', - params: { domain: @instance.domain }, - start_at: @time_period.first - .dashboard__item - = react_admin_component :counter, - end_at: @time_period.last, - label: t('admin.instances.dashboard.instance_followers_measure'), - measure: 'instance_followers', - params: { domain: @instance.domain }, - start_at: @time_period.first - .dashboard__item - = react_admin_component :counter, - end_at: @time_period.last, - href: admin_reports_path(by_target_domain: @instance.domain), - label: t('admin.instances.dashboard.instance_reports_measure'), - measure: 'instance_reports', - params: { domain: @instance.domain }, - start_at: @time_period.first - .dashboard__item - = react_admin_component :dimension, - dimension: 'instance_accounts', - end_at: @time_period.last, - label: t('admin.instances.dashboard.instance_accounts_dimension'), - limit: 8, - params: { domain: @instance.domain }, - start_at: @time_period.first - .dashboard__item - = react_admin_component :dimension, - dimension: 'instance_languages', - end_at: @time_period.last, - label: t('admin.instances.dashboard.instance_languages_dimension'), - limit: 8, - params: { domain: @instance.domain }, - start_at: @time_period.first - + = render 'dashboard', instance_domain: @instance.domain, period_end_at: @time_period.last, period_start_at: @time_period.first - else %p = t('admin.instances.unknown_instance') diff --git a/app/views/admin/invites/_invite.html.haml b/app/views/admin/invites/_invite.html.haml index 8bd5f10feefdc6..53eac1d0cddf89 100644 --- a/app/views/admin/invites/_invite.html.haml +++ b/app/views/admin/invites/_invite.html.haml @@ -2,7 +2,7 @@ %td .input-copy .input-copy__wrapper - %input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: public_invite_url(invite_code: invite.code) } + = copyable_input value: public_invite_url(invite_code: invite.code) %button{ type: :button }= t('generic.copy') %td diff --git a/app/views/admin/tags/show.html.haml b/app/views/admin/tags/show.html.haml index 93387843b2ce41..462ca312a07e86 100644 --- a/app/views/admin/tags/show.html.haml +++ b/app/views/admin/tags/show.html.haml @@ -4,9 +4,7 @@ - content_for :heading_actions do - if current_user.can?(:view_dashboard) .time-period - = l(@time_period.first) - = ' - ' - = l(@time_period.last) + = date_range(@time_period) = link_to t('admin.tags.open'), tag_url(@tag), class: 'button', target: '_blank', rel: 'noopener noreferrer' 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 93daf25f31a74d..0770ac4b810bfb 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 @@ -12,7 +12,7 @@ %li= filter_link_to t('generic.all'), status: nil %li= filter_link_to t('admin.trends.approved'), status: 'approved' %li= filter_link_to t('admin.trends.rejected'), status: 'rejected' - %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{PreviewCardProvider.unreviewed.count})"], ' '), status: 'pending_review' + %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{@pending_preview_card_providers_count.value})"], ' '), status: 'pending_review' .back-link = link_to admin_trends_links_path do = material_symbol 'chevron_left' diff --git a/app/views/admin/trends/tags/index.html.haml b/app/views/admin/trends/tags/index.html.haml index 480877456f5f96..21f6c2947aca37 100644 --- a/app/views/admin/trends/tags/index.html.haml +++ b/app/views/admin/trends/tags/index.html.haml @@ -12,7 +12,7 @@ %li= filter_link_to t('generic.all'), status: nil %li= filter_link_to t('admin.trends.approved'), status: 'approved' %li= filter_link_to t('admin.trends.rejected'), status: 'rejected' - %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Tag.pending_review.count})"], ' '), status: 'pending_review' + %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{@pending_tags_count.value})"], ' '), status: 'pending_review' = form_with model: @form, url: batch_admin_trends_tags_path do |f| = hidden_field_tag :page, params[:page] || 1 diff --git a/app/views/invites/_invite.html.haml b/app/views/invites/_invite.html.haml index 892fdc5a0e38af..7c94062de450bb 100644 --- a/app/views/invites/_invite.html.haml +++ b/app/views/invites/_invite.html.haml @@ -2,7 +2,7 @@ %td .input-copy .input-copy__wrapper - %input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: public_invite_url(invite_code: invite.code) } + = copyable_input value: public_invite_url(invite_code: invite.code) %button{ type: :button }= t('generic.copy') - if invite.valid_for_use? diff --git a/app/views/oauth/authorizations/show.html.haml b/app/views/oauth/authorizations/show.html.haml index a5122a87fc39d7..bdff3363682c07 100644 --- a/app/views/oauth/authorizations/show.html.haml +++ b/app/views/oauth/authorizations/show.html.haml @@ -3,5 +3,5 @@ %p= t('doorkeeper.authorizations.show.title') .input-copy .input-copy__wrapper - %input.oauth-code{ type: 'text', spellcheck: 'false', readonly: true, value: params[:code] } + = copyable_input value: params[:code], class: 'oauth-code' %button{ type: :button }= t('generic.copy') diff --git a/app/views/settings/applications/_form.html.haml b/app/views/settings/applications/_form.html.haml index 66ea8bc12bf00f..85fdefa0fcdf2e 100644 --- a/app/views/settings/applications/_form.html.haml +++ b/app/views/settings/applications/_form.html.haml @@ -18,7 +18,7 @@ .field-group .input.with_block_label - %label= t('activerecord.attributes.doorkeeper/application.scopes') + = form.label t('activerecord.attributes.doorkeeper/application.scopes'), required: true %span.hint= t('simple_form.hints.defaults.scopes') - Doorkeeper.configuration.scopes.group_by { |s| s.split(':').first }.each_value do |value| @@ -29,7 +29,7 @@ hint: false, include_blank: false, item_wrapper_tag: 'li', - label_method: ->(scope) { safe_join([content_tag(:samp, scope, class: class_for_scope(scope)), content_tag(:span, t("doorkeeper.scopes.#{scope}"), class: 'hint')]) }, + label_method: ->(scope) { label_for_scope(scope) }, label: false, required: false, selected: form.object.scopes.all, diff --git a/app/views/settings/applications/index.html.haml b/app/views/settings/applications/index.html.haml index 80eaed5c3994f8..e3011947a64f59 100644 --- a/app/views/settings/applications/index.html.haml +++ b/app/views/settings/applications/index.html.haml @@ -18,7 +18,9 @@ - @applications.each do |application| %tr %td= link_to application.name, settings_application_path(application) - %th= application.scopes + %th + - application.scopes.to_s.split.each do |scope| + = tag.samp(scope, class: 'information-badge', title: t("doorkeeper.scopes.#{scope}")) %td = table_link_to 'close', t('doorkeeper.applications.index.delete'), settings_application_path(application), method: :delete, data: { confirm: t('doorkeeper.applications.confirmations.destroy') } diff --git a/app/views/settings/applications/show.html.haml b/app/views/settings/applications/show.html.haml index 19630cf49b8ccb..bfde27daa96440 100644 --- a/app/views/settings/applications/show.html.haml +++ b/app/views/settings/applications/show.html.haml @@ -15,15 +15,16 @@ %td %code= @application.secret %tr - %th{ rowspan: 2 }= t('applications.your_token') + %th= t('applications.your_token') %td %code= current_user.token_for_app(@application).token %tr + %th %td= table_link_to 'refresh', t('applications.regenerate_token'), regenerate_settings_application_path(@application), method: :post %hr/ -= simple_form_for @application, url: settings_application_path(@application), method: :put do |form| += simple_form_for @application, url: settings_application_path(@application) do |form| = render form .actions diff --git a/app/views/settings/exports/show.html.haml b/app/views/settings/exports/show.html.haml index 320bb0c7cebcbb..5a151be73becce 100644 --- a/app/views/settings/exports/show.html.haml +++ b/app/views/settings/exports/show.html.haml @@ -6,39 +6,39 @@ %tbody %tr %th= t('exports.storage') - %td= number_to_human_size @export.total_storage + %td= number_to_human_size @export_summary.total_storage %td %tr %th= t('accounts.posts_tab_heading') - %td= number_with_delimiter @export.total_statuses + %td= number_with_delimiter @export_summary.total_statuses %td %tr %th= t('admin.accounts.follows') - %td= number_with_delimiter @export.total_follows + %td= number_with_delimiter @export_summary.total_follows %td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv) %tr %th= t('exports.lists') - %td= number_with_delimiter @export.total_lists + %td= number_with_delimiter @export_summary.total_lists %td= table_link_to 'download', t('exports.csv'), settings_exports_lists_path(format: :csv) %tr %th= t('admin.accounts.followers') - %td= number_with_delimiter @export.total_followers + %td= number_with_delimiter @export_summary.total_followers %td %tr %th= t('exports.mutes') - %td= number_with_delimiter @export.total_mutes + %td= number_with_delimiter @export_summary.total_mutes %td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv) %tr %th= t('exports.blocks') - %td= number_with_delimiter @export.total_blocks + %td= number_with_delimiter @export_summary.total_blocks %td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv) %tr %th= t('exports.domain_blocks') - %td= number_with_delimiter @export.total_domain_blocks + %td= number_with_delimiter @export_summary.total_domain_blocks %td= table_link_to 'download', t('exports.csv'), settings_exports_domain_blocks_path(format: :csv) %tr %th= t('exports.bookmarks') - %td= number_with_delimiter @export.total_bookmarks + %td= number_with_delimiter @export_summary.total_bookmarks %td= table_link_to 'download', t('exports.csv'), settings_exports_bookmarks_path(format: :csv) %hr.spacer/ @@ -61,7 +61,8 @@ %tbody - @backups.each do |backup| %tr - %td= l backup.created_at + %td + %time.formatted{ datetime: backup.created_at.iso8601, title: l(backup.created_at) }= l backup.created_at - if backup.processed? %td= number_to_human_size backup.dump_file_size %td= table_link_to 'download', t('exports.archive_takeout.download'), download_backup_url(backup) diff --git a/app/views/settings/imports/index.html.haml b/app/views/settings/imports/index.html.haml index 634631b5aaa4cc..55421991e13173 100644 --- a/app/views/settings/imports/index.html.haml +++ b/app/views/settings/imports/index.html.haml @@ -55,7 +55,10 @@ = t("imports.states.#{import.state}") %td #{import.imported_items} / #{import.total_items} - %td= l(import.created_at) + %td + %time.formatted{ datetime: import.created_at.iso8601, title: l(import.created_at) } + = l(import.created_at) + %td - num_failed = import.processed_items - import.imported_items - if num_failed.positive? diff --git a/app/views/settings/imports/show.html.haml b/app/views/settings/imports/show.html.haml index 4d50049d3d3da5..dd18ac2168c8c7 100644 --- a/app/views/settings/imports/show.html.haml +++ b/app/views/settings/imports/show.html.haml @@ -5,9 +5,9 @@ .flash-message.warning= t('imports.mismatched_types_warning') - if @bulk_import.overwrite? - %p.hint= t("imports.overwrite_preambles.#{@bulk_import.type}_html", filename: @bulk_import.original_filename, total_items: @bulk_import.total_items) + %p.hint= t("imports.overwrite_preambles.#{@bulk_import.type}_html", filename: @bulk_import.original_filename, count: @bulk_import.total_items) - else - %p.hint= t("imports.preambles.#{@bulk_import.type}_html", filename: @bulk_import.original_filename, total_items: @bulk_import.total_items) + %p.hint= t("imports.preambles.#{@bulk_import.type}_html", filename: @bulk_import.original_filename, count: @bulk_import.total_items) .simple_form .actions diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml index b0cd1cba09d63c..0d127bc81de780 100644 --- a/app/views/settings/preferences/appearance/show.html.haml +++ b/app/views/settings/preferences/appearance/show.html.haml @@ -4,7 +4,7 @@ - content_for :heading_actions do = button_tag t('generic.save_changes'), class: 'button', form: 'edit_user' -= simple_form_for current_user, url: settings_preferences_appearance_path, html: { method: :put, id: 'edit_user' } do |f| += simple_form_for current_user, url: settings_preferences_appearance_path, html: { id: :edit_user } do |f| .fields-row .fields-group.fields-row__column.fields-row__column-6 = f.input :locale, diff --git a/app/views/settings/preferences/notifications/show.html.haml b/app/views/settings/preferences/notifications/show.html.haml index 17d5ac20fad68c..9fc293f0a293f9 100644 --- a/app/views/settings/preferences/notifications/show.html.haml +++ b/app/views/settings/preferences/notifications/show.html.haml @@ -4,7 +4,7 @@ - content_for :heading_actions do = button_tag t('generic.save_changes'), class: 'button', form: 'edit_notification' -= simple_form_for current_user, url: settings_preferences_notifications_path, html: { method: :put, id: 'edit_notification' } do |f| += simple_form_for current_user, url: settings_preferences_notifications_path, html: { id: :edit_notification } do |f| = render 'shared/error_messages', object: current_user %h4= t 'notifications.email_events' diff --git a/app/views/settings/preferences/other/show.html.haml b/app/views/settings/preferences/other/show.html.haml index 49d03ca00a612b..b260826fe529f2 100644 --- a/app/views/settings/preferences/other/show.html.haml +++ b/app/views/settings/preferences/other/show.html.haml @@ -4,7 +4,7 @@ - content_for :heading_actions do = button_tag t('generic.save_changes'), class: 'button', form: 'edit_preferences' -= simple_form_for current_user, url: settings_preferences_other_path, html: { method: :put, id: 'edit_preferences' } do |f| += simple_form_for current_user, url: settings_preferences_other_path, html: { id: :edit_preferences } do |f| = render 'shared/error_messages', object: current_user = f.simple_fields_for :settings, current_user.settings do |ff| diff --git a/app/views/settings/privacy/show.html.haml b/app/views/settings/privacy/show.html.haml index 3fb14023b06f09..e8e5bdb906322f 100644 --- a/app/views/settings/privacy/show.html.haml +++ b/app/views/settings/privacy/show.html.haml @@ -5,7 +5,7 @@ %h2= t('settings.profile') = render partial: 'settings/shared/profile_navigation' -= simple_form_for @account, url: settings_privacy_path, html: { method: :put } do |f| += simple_form_for @account, url: settings_privacy_path do |f| = render 'shared/error_messages', object: @account %p.lead= t('privacy.hint_html') diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml index 8fb21325197e3c..427a4fa95ac884 100644 --- a/app/views/settings/profiles/show.html.haml +++ b/app/views/settings/profiles/show.html.haml @@ -5,7 +5,7 @@ %h2= t('settings.profile') = render partial: 'settings/shared/profile_navigation' -= simple_form_for @account, url: settings_profile_path, html: { method: :put, id: 'edit_profile' } do |f| += simple_form_for @account, url: settings_profile_path, html: { id: :edit_profile } do |f| = render 'shared/error_messages', object: @account %p.lead= t('edit_profile.hint_html') @@ -34,7 +34,7 @@ .fields-row__column.fields-row__column-6 .fields-group = f.input :avatar, - hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(Account::Avatar::LIMIT)), + hint: t('simple_form.hints.defaults.avatar', dimensions: Account::Avatar::AVATAR_GEOMETRY, size: number_to_human_size(Account::Avatar::LIMIT)), input_html: { accept: Account::Avatar::IMAGE_MIME_TYPES.join(',') }, wrapper: :with_block_label @@ -50,7 +50,7 @@ .fields-row__column.fields-row__column-6 .fields-group = f.input :header, - hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(Account::Header::LIMIT)), + hint: t('simple_form.hints.defaults.header', dimensions: Account::Header::HEADER_GEOMETRY, size: number_to_human_size(Account::Header::LIMIT)), input_html: { accept: Account::Header::IMAGE_MIME_TYPES.join(',') }, wrapper: :with_block_label diff --git a/app/views/settings/shared/_profile_navigation.html.haml b/app/views/settings/shared/_profile_navigation.html.haml index d490bd75661704..2f81cb5cfdccdf 100644 --- a/app/views/settings/shared/_profile_navigation.html.haml +++ b/app/views/settings/shared/_profile_navigation.html.haml @@ -1,7 +1,7 @@ .content__heading__tabs = render_navigation renderer: :links do |primary| :ruby - primary.item :profile, safe_join([material_symbol('person'), t('settings.edit_profile')]), settings_profile_path - primary.item :privacy, safe_join([material_symbol('lock'), t('privacy.title')]), settings_privacy_path + primary.item :edit_profile, safe_join([material_symbol('person'), t('settings.edit_profile')]), settings_profile_path + primary.item :privacy_reach, safe_join([material_symbol('lock'), t('privacy.title')]), settings_privacy_path primary.item :verification, safe_join([material_symbol('check'), t('verification.verification')]), settings_verification_path primary.item :featured_tags, safe_join([material_symbol('tag'), t('settings.featured_tags')]), settings_featured_tags_path diff --git a/app/views/settings/two_factor_authentication/confirmations/new.html.haml b/app/views/settings/two_factor_authentication/confirmations/new.html.haml index 0b8278a104eaea..a35479b84e6850 100644 --- a/app/views/settings/two_factor_authentication/confirmations/new.html.haml +++ b/app/views/settings/two_factor_authentication/confirmations/new.html.haml @@ -5,7 +5,7 @@ %p.hint= t('otp_authentication.instructions_html') .qr-wrapper - .qr-code!= @qrcode.as_svg(padding: 0, module_size: 4) + .qr-code!= @qrcode.as_svg(padding: 0, module_size: 4, use_path: true) .qr-alternative %p.hint= t('otp_authentication.manual_instructions') diff --git a/app/views/settings/verifications/show.html.haml b/app/views/settings/verifications/show.html.haml index 5318b0767ddfb0..560807f27ca7fb 100644 --- a/app/views/settings/verifications/show.html.haml +++ b/app/views/settings/verifications/show.html.haml @@ -16,7 +16,7 @@ .input-copy.lead .input-copy__wrapper - %input{ type: :text, maxlength: '999', spellcheck: 'false', readonly: 'true', value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: 'me').to_str } + = copyable_input value: link_to('Mastodon', ActivityPub::TagManager.instance.url_for(@account), rel: :me) %button{ type: :button }= t('generic.copy') %p.lead= t('verification.extra_instructions_html') @@ -31,7 +31,7 @@ = material_symbol 'check', class: 'verified-badge__mark' %span= field.value -= simple_form_for @account, url: settings_verification_path, html: { method: :put, class: 'form-section' } do |f| += simple_form_for @account, url: settings_verification_path, html: { class: 'form-section' } do |f| = render 'shared/error_messages', object: @account %h3= t('author_attribution.title') @@ -50,13 +50,13 @@ = image_tag frontend_asset_url('images/preview.png'), alt: '', class: 'status-card__image-image' .status-card__content %span.status-card__host - %span= t('author_attribution.s_blog', name: @account.username) + %span= t('author_attribution.s_blog', name: display_name(@account)) · %time.time-ago{ datetime: 1.year.ago.to_date.iso8601 } %strong.status-card__title= t('author_attribution.example_title') .more-from-author = logo_as_symbol(:icon) - = t('author_attribution.more_from_html', name: link_to(root_url, class: 'story__details__shared__author-link') { image_tag(@account.avatar.url, class: 'account__avatar', width: 16, height: 16, alt: '') + content_tag(:bdi, display_name(@account)) }) + = t('author_attribution.more_from_html', name: link_to(root_url, class: 'story__details__shared__author-link') { image_tag(@account.avatar.url, class: 'account__avatar', width: 16, height: 16, alt: '') + tag.bdi(display_name(@account)) }) .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/severed_relationships/index.html.haml b/app/views/severed_relationships/index.html.haml index 7c599e9c0e7e55..cc9439b4681eed 100644 --- a/app/views/severed_relationships/index.html.haml +++ b/app/views/severed_relationships/index.html.haml @@ -15,7 +15,9 @@ %tbody - @events.each do |event| %tr - %td= l event.created_at + %td + %time.formatted{ datetime: event.created_at.iso8601, title: l(event.created_at) } + = l(event.created_at) %td= t("severed_relationships.event_type.#{event.type}", target_name: event.target_name) - if event.purged? %td{ rowspan: 2 }= t('severed_relationships.purged') diff --git a/app/workers/filtered_notification_cleanup_worker.rb b/app/workers/filtered_notification_cleanup_worker.rb index 2b955da3c0a1ac..87ff6a9eb5e928 100644 --- a/app/workers/filtered_notification_cleanup_worker.rb +++ b/app/workers/filtered_notification_cleanup_worker.rb @@ -4,6 +4,6 @@ class FilteredNotificationCleanupWorker include Sidekiq::Worker def perform(account_id, from_account_id) - Notification.where(account_id: account_id, from_account_id: from_account_id, filtered: true).reorder(nil).in_batches(order: :desc).delete_all + Notification.where(account_id: account_id, from_account_id: from_account_id, filtered: true).in_batches(order: :desc).delete_all end end diff --git a/app/workers/mention_resolve_worker.rb b/app/workers/mention_resolve_worker.rb new file mode 100644 index 00000000000000..72dcd9633f32fe --- /dev/null +++ b/app/workers/mention_resolve_worker.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class MentionResolveWorker + include Sidekiq::Worker + include ExponentialBackoff + include JsonLdHelper + + sidekiq_options queue: 'pull', retry: 7 + + def perform(status_id, uri, options = {}) + status = Status.find_by(id: status_id) + return if status.nil? + + account = account_from_uri(uri) + account = ActivityPub::FetchRemoteAccountService.new.call(uri, request_id: options[:request_id]) if account.nil? + + return if account.nil? + + status.mentions.create!(account: account, silent: false) + rescue ActiveRecord::RecordNotFound + # Do nothing + rescue Mastodon::UnexpectedResponseError => e + response = e.response + + if response_error_unsalvageable?(response) + # Give up + else + raise e + end + end + + private + + def account_from_uri(uri) + ActivityPub::TagManager.instance.uri_to_resource(uri, Account) + end +end diff --git a/app/workers/scheduler/user_cleanup_scheduler.rb b/app/workers/scheduler/user_cleanup_scheduler.rb index 9f58d9225b3a14..f7551283320dce 100644 --- a/app/workers/scheduler/user_cleanup_scheduler.rb +++ b/app/workers/scheduler/user_cleanup_scheduler.rb @@ -16,7 +16,7 @@ def perform private def clean_unconfirmed_accounts! - User.unconfirmed.where(confirmation_sent_at: ..UNCONFIRMED_ACCOUNTS_MAX_AGE_DAYS.days.ago).reorder(nil).find_in_batches do |batch| + User.unconfirmed.where(confirmation_sent_at: ..UNCONFIRMED_ACCOUNTS_MAX_AGE_DAYS.days.ago).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 diff --git a/app/workers/web/push_notification_worker.rb b/app/workers/web/push_notification_worker.rb index 7e9691aaba37cd..104503f130fc2d 100644 --- a/app/workers/web/push_notification_worker.rb +++ b/app/workers/web/push_notification_worker.rb @@ -16,10 +16,10 @@ def perform(subscription_id, notification_id) # in the meantime, so we have to double-check before proceeding return unless @notification.activity.present? && @subscription.pushable?(@notification) - payload = @subscription.encrypt(push_notification_json) + payload = web_push_request.encrypt(push_notification_json) - request_pool.with(@subscription.audience) do |http_client| - request = Request.new(:post, @subscription.endpoint, body: payload.fetch(:ciphertext), http_client: http_client) + request_pool.with(web_push_request.audience) do |http_client| + request = Request.new(:post, web_push_request.endpoint, body: payload.fetch(:ciphertext), http_client: http_client) request.add_headers( 'Content-Type' => 'application/octet-stream', @@ -27,8 +27,8 @@ def perform(subscription_id, notification_id) 'Urgency' => URGENCY, 'Content-Encoding' => 'aesgcm', 'Encryption' => "salt=#{Webpush.encode64(payload.fetch(:salt)).delete('=')}", - 'Crypto-Key' => "dh=#{Webpush.encode64(payload.fetch(:server_public_key)).delete('=')};#{@subscription.crypto_key_header}", - 'Authorization' => @subscription.authorization_header + 'Crypto-Key' => "dh=#{Webpush.encode64(payload.fetch(:server_public_key)).delete('=')};#{web_push_request.crypto_key_header}", + 'Authorization' => web_push_request.authorization_header ) request.perform do |response| @@ -50,17 +50,27 @@ def perform(subscription_id, notification_id) private + def web_push_request + @web_push_request || WebPushRequest.new(@subscription) + end + def push_notification_json - json = I18n.with_locale(@subscription.locale.presence || I18n.default_locale) do - ActiveModelSerializers::SerializableResource.new( - @notification, - serializer: Web::NotificationSerializer, - scope: @subscription, - scope_name: :current_push_subscription - ).as_json + Oj.dump(serialized_notification_in_subscription_locale.as_json) + end + + def serialized_notification_in_subscription_locale + I18n.with_locale(@subscription.locale.presence || I18n.default_locale) do + serialized_notification end + end - Oj.dump(json) + def serialized_notification + ActiveModelSerializers::SerializableResource.new( + @notification, + serializer: Web::NotificationSerializer, + scope: @subscription, + scope_name: :current_push_subscription + ) end def request_pool diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 26c722da60ea28..16330734736209 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -74,8 +74,8 @@ ignore_unused: - 'admin_mailer.*.subject' - 'user_mailer.*.subject' - 'notification_mailer.*' - - 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html' - - 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html' + - 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html.*' + - 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html.*' - 'mail_subscriptions.unsubscribe.emails.*' - 'preferences.other' # some locales are missing other keys, therefore leading i18n-tasks to detect `preferences` as plural and not finding use - 'edit_profile.other' # some locales are missing other keys, therefore leading i18n-tasks to detect `preferences` as plural and not finding use diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index b47e76c08bc60a..de1c75f576ec8e 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -9,16 +9,9 @@ current_user || redirect_to(new_user_session_url) end - resource_owner_from_credentials do |_routes| - user = User.authenticate_with_ldap(email: request.params[:username], password: request.params[:password]) if Devise.ldap_authentication - user ||= User.authenticate_with_pam(email: request.params[:username], password: request.params[:password]) if Devise.pam_authentication - - if user.nil? - user = User.find_by(email: request.params[:username]) - user = nil unless user&.valid_password?(request.params[:password]) - end - - user unless user&.otp_required_for_login? + # Disable Resource Owner Password Credentials Grant Flow + resource_owner_from_credentials do + nil end # Doorkeeper provides some administrative interfaces for managing OAuth @@ -169,7 +162,7 @@ # http://tools.ietf.org/html/rfc6819#section-4.4.3 # - grant_flows %w(authorization_code password client_credentials) + grant_flows %w(authorization_code client_credentials) # Under some circumstances you might want to have applications auto-approved, # so that the user skips the authorization step. diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 965f354a35f82c..ced8de4ef28a76 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -446,6 +446,7 @@ ca: title: Blocar el nou domini de correu-e no_email_domain_block_selected: No s'han canviat els bloqueigs de domini perquè no se n'ha seleccionat cap not_permitted: No permés + resolved_dns_records_hint_html: El nom del domini resol als següents dominis MX, que són els responsables finals per a acceptar els correus. Blocar un domini MX blocarà els registres des de qualsevol adreça de correu que utilitzi el mateix domini MX, encara que el nom visible sigui diferent. Vigileu de no blocar els grans proveïdors de correu. resolved_through_html: Resolt mitjançant %{domain} title: Dominis de correu-e blocats export_domain_allows: @@ -800,6 +801,7 @@ ca: destroyed_msg: La càrrega al lloc s'ha suprimit correctament! software_updates: critical_update: Crítica - si us plau, actualitza ràpidament + description: Es recomana de mantenir actualizada la instal·lació de Mastodon per a beneficiar-se de les darreres correccions i característiques. A més, de vegades és fonamental actualitzar-la per a evitar problemes de seguretat. Per això Mastodon comprova si hi ha actualitzacions cada 30 minuts i us notificarà d'acord amb les preferències de notificacions de correu electrònic. documentation_link: Més informació release_notes: Notes de llançament title: Actualitzacions disponibles @@ -1155,6 +1157,7 @@ ca: account_status: Estat del compte confirming: Esperant que es completi la confirmació del correu-e. functional: El teu compte està completament operatiu. + pending: La vostra sol·licitud està pendent de revisió pel nostre personal. Això pot trigar una mica. Rebreu un correu electrònic quan s'aprovi. redirecting_to: El teu compte és inactiu perquè actualment està redirigint a %{acct}. self_destruct: Com que %{domain} tanca, només tindreu accés limitat al vostre compte. view_strikes: Veure accions del passat contra el teu compte @@ -1202,6 +1205,9 @@ ca: before: 'Abans de procedir, llegiu amb cura aquestes notes:' caches: El contingut que ha estat memoritzat en la memòria cau per altres servidors pot persistir data_removal: Els teus tuts i altres dades seran permanentment eliminades + email_change_html: Podeu canviar l'adreça de correu sense eliminar el vostre compte + email_contact_html: Si encara no arriba, podeu enviar un correu-e a %{email} per a demanar ajuda + email_reconfirmation_html: Si no rebeu el correu electrònic de confirmació , podeu tornar-lo a demanar irreversible: No seràs capaç de restaurar o reactivar el teu compte more_details_html: Per a més detalls, llegeix la política de privadesa. username_available: El teu nom d'usuari esdevindrà altre cop disponible diff --git a/config/locales/cy.yml b/config/locales/cy.yml index 1ae6aa08fff93a..a70d08ed8e5ef0 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -931,6 +931,9 @@ cy: message_html: Nid ydych wedi diffinio unrhyw reolau gweinydd. sidekiq_process_check: message_html: Does dim proses Sidekiq yn rhedeg ar gyfer y ciw(iau) %{value}. Adolygwch eich ffurfweddiad Sidekiq + software_version_check: + action: Gweld y diweddariadau sydd ar gael + message_html: Mae diweddariad Mastodon ar gael. software_version_critical_check: action: Gweld y diweddariadau sydd ar gael message_html: Mae diweddariad hanfodol Mastodon ar gael, diweddarwch cyn gynted â phosibl. @@ -1796,6 +1799,7 @@ cy: delete: Dileu cyfrif development: Datblygu edit_profile: Golygu proffil + export: Allforio featured_tags: Prif hashnodau import: Mewnforio import_and_export: Mewnforio ac allforio diff --git a/config/locales/de.yml b/config/locales/de.yml index c82e65282ffe3e..7a8469df614887 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -79,7 +79,7 @@ de: invite_request_text: Begründung für das Beitreten invited_by: Eingeladen von ip: IP-Adresse - joined: Beigetreten + joined: Mitglied seit location: all: Alle local: Lokal diff --git a/config/locales/doorkeeper.el.yml b/config/locales/doorkeeper.el.yml index 59877b6bd06766..984eff887127c4 100644 --- a/config/locales/doorkeeper.el.yml +++ b/config/locales/doorkeeper.el.yml @@ -60,6 +60,7 @@ el: error: title: Εμφανίστηκε σφάλμα new: + prompt_html: Το %{client_name} επιθυμεί το δικαίωμα πρόσβασης στον λογαριασμό σας. Εγκρίνετε αυτό το αίτημα μόνο αν αναγνωρίζετε και εμπιστεύεστε αυτήν την πηγή. review_permissions: Ανασκόπηση δικαιωμάτων title: Απαιτείται έγκριση show: diff --git a/config/locales/doorkeeper.gl.yml b/config/locales/doorkeeper.gl.yml index adee6bd3d3ccb4..5d7148b84b0284 100644 --- a/config/locales/doorkeeper.gl.yml +++ b/config/locales/doorkeeper.gl.yml @@ -69,7 +69,7 @@ gl: buttons: revoke: Retirar autorización confirmations: - revoke: Estás segura? + revoke: Tes certeza? index: authorized_at: Autorizada o %{date} description_html: Estas aplicacións poden acceder á túa conta usando a API. Se ves aplicacións que non recoñeces, ou hai comportamentos non consentidos dalgunha delas, podes revogar o acceso. diff --git a/config/locales/el.yml b/config/locales/el.yml index 610ae4026512a7..4496ec51a67f8a 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -953,6 +953,7 @@ el: used_by_over_week: one: Χρησιμοποιήθηκε από ένα άτομο την τελευταία εβδομάδα other: Χρησιμοποιήθηκε από %{count} άτομα την τελευταία εβδομάδα + title: Προτάσεις και τάσεις trending: Τάσεις warning_presets: add_new: Πρόσθεση νέου @@ -1037,7 +1038,9 @@ el: guide_link_text: Μπορεί να συνεισφέρει ο οποιοσδήποτε. sensitive_content: Ευαίσθητο περιεχόμενο application_mailer: + notification_preferences: Αλλαγή προτιμήσεων email salutation: "%{name}," + settings: 'Αλλαγή προτιμήσεων email: %{link}' unsubscribe: Κατάργηση εγγραφής view: 'Προβολή:' view_profile: Προβολή προφίλ @@ -1084,6 +1087,7 @@ el: or_log_in_with: Ή συνδέσου με privacy_policy_agreement_html: Έχω διαβάσει και συμφωνώ με την πολιτική απορρήτου progress: + confirm: Επιβεβαίωση email details: Τα στοιχεία σας review: Η αξιολόγησή μας rules: Αποδοχή κανόνων @@ -1123,6 +1127,8 @@ el: view_strikes: Προβολή προηγούμενων ποινών εναντίον του λογαριασμού σας too_fast: Η φόρμα υποβλήθηκε πολύ γρήγορα, προσπαθήστε ξανά. use_security_key: Χρήση κλειδιού ασφαλείας + author_attribution: + example_title: Δείγμα κειμένου challenge: confirm: Συνέχεια hint_html: "Συμβουλή: Δεν θα σου ζητήσουμε τον κωδικό ασφαλείας σου ξανά για την επόμενη ώρα." @@ -1342,7 +1348,10 @@ el: time_started: Ξεκίνησε στις titles: blocking: Εισαγωγή αποκλεισμένων λογαριασμών + bookmarks: Εισαγωγή σελιδοδεικτών + domain_blocking: Εισαγωγή αποκλεισμένων τομέων following: Εισαγωγή λογαριασμών που ακολουθείτε + lists: Εισαγωγή λιστών type: Τύπος εισαγωγής type_groups: destructive: Μπλοκ & σίγαση @@ -1351,6 +1360,7 @@ el: bookmarks: Σελιδοδείκτες domain_blocking: Λίστα αποκλεισμένων τομέων following: Λίστα ατόμων που ακολουθείτε + lists: Λίστες muting: Λίστα αποσιωπήσεων upload: Μεταμόρφωση invites: @@ -1365,6 +1375,7 @@ el: '86400': 1 μέρα expires_in_prompt: Ποτέ generate: Δημιουργία συνδέσμου πρόσκλησης + invalid: Αυτή η πρόσκληση δεν είναι έγκυρη invited_by: 'Σε προσκάλεσε ο/η:' max_uses: one: 1 χρήσης @@ -1388,6 +1399,11 @@ el: failed_sign_in_html: Αποτυχημένη προσπάθεια σύνδεσης με %{method} από %{ip} (%{browser}) successful_sign_in_html: Επιτυχής σύνδεση με %{method} από %{ip} (%{browser}) title: Ιστορικό ελέγχου ταυτότητας + mail_subscriptions: + unsubscribe: + action: Ναι, κατάργηση συνδρομής + complete: Η συνδρομή καταργήθηκε + title: Κατάργηση συνδρομής media_attachments: validations: images_and_video: Δεν γίνεται να προσθέσεις βίντεο σε ανάρτηση που ήδη περιέχει εικόνες @@ -1467,6 +1483,7 @@ el: update: subject: "%{name} επεξεργάστηκε μια ανάρτηση" notifications: + email_events: Συμβάντα για ειδοποιήσεις μέσω email email_events_hint: 'Επέλεξε συμβάντα για τα οποία θέλεις να λαμβάνεις ειδοποιήσεις μέσω email:' number: human: @@ -1507,12 +1524,18 @@ el: other: Άλλες posting_defaults: Προεπιλογές ανάρτησης public_timelines: Δημόσιες ροές + privacy: + privacy: Απόρρητο + search: Αναζήτηση privacy_policy: title: Πολιτική Απορρήτου reactions: errors: limit_reached: Το όριο διαφορετικών αντιδράσεων ξεπεράστηκε unrecognized_emoji: δεν είναι ένα αναγνωρισμένο emoji + redirects: + prompt: Αν εμπιστεύεστε αυτόν τον σύνδεσμο, κάντε κλικ σε αυτόν για να συνεχίσετε. + title: Αποχωρείτε από το %{instance}. relationships: activity: Δραστηριότητα λογαριασμού confirm_follow_selected_followers: Είσαι βέβαιος ότι θες να ακολουθήσεις τους επιλεγμένους ακόλουθους; @@ -1548,6 +1571,9 @@ el: over_daily_limit: Έχεις υπερβεί το όριο των %{limit} προγραμματισμένων αναρτήσεων για εκείνη τη μέρα over_total_limit: Έχεις υπερβεί το όριο των %{limit} προγραμματισμένων αναρτήσεων too_soon: Η προγραμματισμένη ημερομηνία πρέπει να είναι στο μέλλον + self_destruct: + lead_html: Δυστυχώς, το %{domain} κλείνει οριστικά. Αν είχατε λογαριασμό εκεί, δεν θα μπορείτε να συνεχίσετε τη χρήση του, αλλά μπορείτε ακόμα να ζητήσετε ένα αντίγραφο ασφαλείας των δεδομένων σας. + title: Αυτός ο διακομιστής κλείνει οριστικά sessions: activity: Τελευταία δραστηριότητα browser: Φυλλομετρητής @@ -1604,10 +1630,12 @@ el: delete: Διαγραφή λογαριασμού development: Ανάπτυξη edit_profile: Επεξεργασία προφίλ + export: Εξαγωγή featured_tags: Παρεχόμενες ετικέτες import: Εισαγωγή import_and_export: Εισαγωγή και εξαγωγή migrate: Μετακόμιση λογαριασμού + notifications: Ειδοποιήσεις μέσω email preferences: Προτιμήσεις profile: Προφίλ relationships: Ακολουθείς και σε ακολουθούν @@ -1615,6 +1643,12 @@ el: strikes: Παραπτώματα από ομάδα συντονισμού two_factor_authentication: Πιστοποίηση 2 παραγόντων webauthn_authentication: Κλειδιά ασφαλείας + severed_relationships: + download: Λήψη (%{count}) + event_type: + account_suspension: Αναστολή λογαριασμού (%{target_name}) + domain_block: Αναστολή διακομιστή (%{target_name}) + type: Συμβάν statuses: attached: audio: @@ -1697,11 +1731,13 @@ el: contrast: Mastodon (Υψηλή αντίθεση) default: Mastodon (Σκοτεινό) mastodon-light: Mastodon (Ανοιχτόχρωμο) + system: Αυτόματο (θέμα συστήματος) time: formats: default: "%b %d, %Y, %H:%M" month: "%b %Y" time: "%H:%M" + with_time_zone: "%d %b %Y, %H:%M %Z" two_factor_authentication: add: Προσθήκη disable: Απενεργοποίηση 2FA @@ -1789,6 +1825,10 @@ el: feature_action: Μάθε περισσότερα feature_audience: Το Mastodon σού παρέχει μια μοναδική δυνατότητα διαχείρισης του κοινού σου χωρίς μεσάζοντες. Το Mastodon όταν αναπτύσσεται στη δική σου υποδομή σού επιτρέπει να ακολουθείς και να ακολουθείσαι από οποιονδήποτε άλλο συνδεδεμένο διακομιστή Mastodon και κανείς δεν τον ελέγχει, εκτός από σένα. feature_audience_title: Χτίσε το κοινό σου με σιγουριά + post_action: Σύνθεση + share_action: Κοινοποίηση + share_title: Μοιραστείτε το προφίλ σας στο Mastodon + sign_in_action: Σύνδεση subject: Καλώς ήρθες στο Mastodon title: Καλώς όρισες, %{name}! users: @@ -1798,7 +1838,10 @@ el: otp_lost_help_html: Αν χάσεις πρόσβαση και στα δύο, μπορείς να επικοινωνήσεις με %{email} signed_in_as: 'Έχεις συνδεθεί ως:' verification: + here_is_how: Δείτε πώς verification: Πιστοποίηση + verified_links: Οι επαληθευμένοι σύνδεσμοι σας + website_verification: Επαλήθευση ιστοτόπου webauthn_credentials: add: Προσθήκη νέου κλειδιού ασφαλείας create: diff --git a/config/locales/en.yml b/config/locales/en.yml index bf45dff33af855..42327ae183af0a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1366,19 +1366,43 @@ en: overwrite: Overwrite overwrite_long: Replace current records with the new ones overwrite_preambles: - blocking_html: You are about to replace your block list with up to %{total_items} accounts from %{filename}. - bookmarks_html: You are about to replace your bookmarks with up to %{total_items} posts from %{filename}. - domain_blocking_html: You are about to replace your domain block list with up to %{total_items} domains from %{filename}. - following_html: You are about to follow up to %{total_items} accounts from %{filename} and stop following anyone else. - lists_html: You are about to replace your lists with contents of %{filename}. Up to %{total_items} accounts will be added to new lists. - muting_html: You are about to replace your list of muted accounts with up to %{total_items} accounts from %{filename}. + blocking_html: + one: You are about to replace your block list with up to %{count} account from %{filename}. + other: You are about to replace your block list with up to %{count} accounts from %{filename}. + bookmarks_html: + one: You are about to replace your bookmarks with up to %{count} post from %{filename}. + other: You are about to replace your bookmarks with up to %{count} posts from %{filename}. + domain_blocking_html: + one: You are about to replace your domain block list with up to %{count} domain from %{filename}. + other: You are about to replace your domain block list with up to %{count} domains from %{filename}. + following_html: + one: You are about to follow up to %{count} account from %{filename} and stop following anyone else. + other: You are about to follow up to %{count} accounts from %{filename} and stop following anyone else. + lists_html: + one: You are about to replace your lists with contents of %{filename}. Up to %{count} account will be added to new lists. + other: You are about to replace your lists with contents of %{filename}. Up to %{count} accounts will be added to new lists. + muting_html: + one: You are about to replace your list of muted account with up to %{count} account from %{filename}. + other: You are about to replace your list of muted accounts with up to %{count} accounts from %{filename}. preambles: - blocking_html: You are about to block up to %{total_items} accounts from %{filename}. - bookmarks_html: You are about to add up to %{total_items} posts from %{filename} to your bookmarks. - domain_blocking_html: You are about to block up to %{total_items} domains from %{filename}. - following_html: You are about to follow up to %{total_items} accounts from %{filename}. - lists_html: You are about to add up to %{total_items} accounts from %{filename} to your lists. New lists will be created if there is no list to add to. - muting_html: You are about to mute up to %{total_items} accounts from %{filename}. + blocking_html: + one: You are about to block up to %{count} account from %{filename}. + other: You are about to block up to %{count} accounts from %{filename}. + bookmarks_html: + one: You are about to add up to %{count} post from %{filename} to your bookmarks. + other: You are about to add up to %{count} posts from %{filename} to your bookmarks. + domain_blocking_html: + one: You are about to block up to %{count} domain from %{filename}. + other: You are about to block up to %{count} domains from %{filename}. + following_html: + one: You are about to follow up to %{count} account from %{filename}. + other: You are about to follow up to %{count} accounts from %{filename}. + lists_html: + one: You are about to add up to %{count} account from %{filename} to your lists. New lists will be created if there is no list to add to. + other: You are about to add up to %{count} accounts from %{filename} to your lists. New lists will be created if there is no list to add to. + muting_html: + one: You are about to mute up to %{count} account from %{filename}. + other: You are about to mute up to %{count} accounts from %{filename}. preface: You can import data that you have exported from another server, such as a list of the people you are following or blocking. recent_imports: Recent imports states: diff --git a/config/locales/eo.yml b/config/locales/eo.yml index a3f968d1396bad..10b297f1a8b70c 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -218,18 +218,22 @@ eo: update_custom_emoji: Ĝisdatigi proprajn emoĝiojn update_domain_block: Ĝigdatigi domajnan blokadon update_ip_block: Krei IP-regulon + update_report: Ĝisdatigo de Raporto update_status: Ĝisdatigi afiŝon update_user_role: Ĝisdatigi rolon actions: approve_appeal_html: "%{name} aprobis apelacion kontraŭ moderiga decido de %{target}" approve_user_html: "%{name} aprobis registriĝon de %{target}" assigned_to_self_report_html: "%{name} asignis signalon %{target} al si mem" + change_email_user_html: "%{name} ŝanĝis retadreson de uzanto %{target}" change_role_user_html: "%{name} ŝanĝis rolon de %{target}" + confirm_user_html: "%{name} konfirmis retadreson de uzanto %{target}" create_account_warning_html: "%{name} sendis averton al %{target}" create_announcement_html: "%{name} kreis novan anoncon %{target}" create_custom_emoji_html: "%{name} alŝutis novan emoĝion %{target}" create_domain_allow_html: "%{name} aldonis domajnon %{target} al la blanka listo" create_domain_block_html: "%{name} blokis domajnon %{target}" + create_email_domain_block_html: "%{name} blokis retpoŝtan domajnon %{target}" create_ip_block_html: "%{name} kreis regulon por IP %{target}" create_unavailable_domain_html: "%{name} ĉesis sendon al domajno %{target}" create_user_role_html: "%{name} kreis rolon de %{target}" @@ -238,6 +242,7 @@ eo: destroy_custom_emoji_html: "%{name} forigis emoĝion %{target}" destroy_domain_allow_html: "%{name} forigis domajnon %{target} el la blanka listo" destroy_domain_block_html: "%{name} malblokis domajnon %{target}" + destroy_email_domain_block_html: "%{name} malblokis retpoŝtan domajnon %{target}" destroy_instance_html: "%{name} forigis domajnon %{target}" destroy_ip_block_html: "%{name} forigis regulon por IP %{target}" destroy_status_html: "%{name} forigis mesaĝojn de %{target}" diff --git a/config/locales/gd.yml b/config/locales/gd.yml index 90d03c74e15fdb..a030b0d18584e1 100644 --- a/config/locales/gd.yml +++ b/config/locales/gd.yml @@ -903,6 +903,9 @@ gd: message_html: Cha do mhìnich thu riaghailtean an fhrithealaiche fhathast. sidekiq_process_check: message_html: Chan eil pròiseas Sidekiq sam bith a ruith dhan chiutha/dha na ciuthan %{value}. Thoir sùil air an rèiteachadh Sidekiq agad + software_version_check: + action: Faic na h-ùrachaidhean a tha ri fhaighinn + message_html: Tha ùrachadh Mastodon ri fhaighinn. software_version_critical_check: action: Faic na h-ùrachaidhean a tha ri fhaighinn message_html: Tha ùrachadh èiginneach air Mastodon ri fhaighinn, ùraich cho luath ’s a ghabhas. @@ -1021,7 +1024,7 @@ gd: delete: Sguab às edit_preset: Deasaich rabhadh ro-shuidhichte empty: Cha do mhìnich thu ro-sheataichean rabhaidhean fhathast. - title: Ro-sheataichean rabhaidhean + title: Rabhaidhean ro-shocraichte webhooks: add_new: Cuir puing-dheiridh ris delete: Sguab às @@ -1744,6 +1747,7 @@ gd: delete: Sguabadh às cunntais development: Leasachadh edit_profile: Deasaich a’ phròifil + export: Às-phortadh featured_tags: Tagaichean hais brosnaichte import: Ion-phortadh import_and_export: Ion-phortadh ⁊ às-phortadh diff --git a/config/locales/he.yml b/config/locales/he.yml index c7af22660f7b16..846b0d14af94aa 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -903,6 +903,9 @@ he: message_html: לא הוגדרו שום כללי שרת. sidekiq_process_check: message_html: שום הליכי Sidekiq לא רצים עבור %{value} תור(ות). בחנו בבקשה את הגדרות Sidekiq + software_version_check: + action: ראו עדכונים זמינים + message_html: עדכון מסטודון זמין כעת. software_version_critical_check: action: ראו עדכונים זמינים message_html: יצא עדכון קריטי למסטודון, נא לעדכן את תוכנת מסטודון בהקדם האפשרי. @@ -1744,6 +1747,7 @@ he: delete: מחיקת חשבון development: פיתוח edit_profile: עריכת פרופיל + export: ייצוא featured_tags: תגיות נבחרות import: יבוא import_and_export: יבוא ויצוא diff --git a/config/locales/kab.yml b/config/locales/kab.yml index 12bda84d463d2a..993488f1fc0934 100644 --- a/config/locales/kab.yml +++ b/config/locales/kab.yml @@ -264,6 +264,8 @@ kab: domain: Taɣult new: create: Rnu taɣult + export_domain_allows: + no_file: Ula d yiwen ufaylu ma yettwafran export_domain_blocks: no_file: Ulac afaylu yettwafernen follow_recommendations: @@ -529,6 +531,10 @@ kab: account_status: Addad n umiḍan functional: Amiḍan-inek·inem yetteddu s lekmal-is. use_security_key: Seqdec tasarut n teɣlist + author_attribution: + example_title: Amedya n weḍris + more_from_html: Ugar s ɣur %{name} + s_blog: Ablug n %{name} challenge: confirm: Kemmel invalid_password: Yir awal uffir @@ -685,6 +691,9 @@ kab: subject: Yuder-ik·ikem-id %{name} reblog: subject: "%{name} yesselha addad-ik·im" + title: Azuzer amaynut + status: + subject: "%{name} akken i d-y·t·essufeɣ" number: human: decimal_units: diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 16844a95c2bd4c..2cc8ff6a497b72 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -34,6 +34,7 @@ lv: created_msg: Moderācijas piezīme ir veiksmīgi izveidota! destroyed_msg: Moderācijas piezīme ir veiksmīgi iznīcināta! accounts: + add_email_domain_block: Liegt e-pasta domēnu approve: Apstiprināt approved_msg: Veiksmīgi apstiprināts %{username} reģistrēšanās pieteikums are_you_sure: Vai esi pārliecināts? @@ -61,6 +62,7 @@ lv: demote: Pazemināt destroyed_msg: Lietotāja %{username} dati tagad ievietoti rindā, lai tos nekavējoties izdzēstu disable: Iesaldēt + disable_sign_in_token_auth: Atspējot autentificēšanos ar e-pasta pilnvaru disable_two_factor_authentication: Atspējot 2FA disabled: Iesaldēts display_name: Parādāmais vārds @@ -69,6 +71,7 @@ lv: email: E-pasts email_status: E-pasta statuss enable: Atsaldēt + enable_sign_in_token_auth: Iespējot autentificēšanos ar e-pasta pilnvaru enabled: Iespējots enabled_msg: Veiksmīgi atsaldēts %{username} konts followers: Sekotāji @@ -180,17 +183,21 @@ lv: confirm_user: Apstiprināt lietotāju create_account_warning: Izveidot Brīdinājumu create_announcement: Izveidot Paziņojumu + create_canonical_email_block: Izveidot e-pasta liegumu create_custom_emoji: Izveidot pielāgotu emocijzīmi create_domain_allow: Izveidot Domēna Atļauju create_domain_block: Izveidot Domēna Bloku + create_email_domain_block: Izveidot e-pasta domēna liegumu create_ip_block: Izveidot IP noteikumu create_unavailable_domain: Izveidot Nepieejamu Domēnu create_user_role: Izveidot lomu demote_user: Pazemināt Lietotāju destroy_announcement: Dzēst Paziņojumu + destroy_canonical_email_block: Izdzēst e-pasta liegumu destroy_custom_emoji: Dzēst pielāgoto emocijzīmi destroy_domain_allow: Dzēst Domēna Atļauju destroy_domain_block: Dzēst Domēna Bloku + destroy_email_domain_block: Izdzēst e-pasta domēna liegumu destroy_instance: Attīrīt domēnu destroy_ip_block: Dzēst IP noteikumu destroy_status: Izdzēst Rakstu diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 8f6afc2426bb9b..ca5e34ee55d80d 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -1,7 +1,7 @@ --- nn: about: - about_mastodon_html: 'Framtidas sosiale nettverk: Ingen annonsar, ingen verksemder som overvaker deg, etisk design og desentralisering! Eig idéane dine med Mastodon!' + about_mastodon_html: 'Framtidas sosiale nettverk: Ingen annonsar, ingen verksemder som overvaker deg, etisk design og desentralisering! Eig dataene dine med Mastodon!' contact_missing: Ikkje sett contact_unavailable: I/T hosted_on: "%{domain} er vert for Mastodon" @@ -39,7 +39,7 @@ nn: avatar: Bilete by_domain: Domene change_email: - changed_msg: Konto-e-posten er endra! + changed_msg: E-post for konto er endra! current_email: Noverande e-post label: Byt e-post new_email: Ny e-post @@ -62,7 +62,7 @@ nn: disable: Slå av disable_sign_in_token_auth: Slå av e-post-token-autentisering disable_two_factor_authentication: Slå av 2FA - disabled: Slege av + disabled: Inaktiv display_name: Synleg namn domain: Domene edit: Rediger diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 5e7317c5fbb730..6451e7c601ace5 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -1888,7 +1888,7 @@ pt-BR: none: Aviso sensitive: Conta marcada como sensível silence: Conta silenciada - suspend: Conta banida + suspend: Conta suspensa welcome: apps_android_action: Disponível no Google Play apps_ios_action: Disponível na App Store diff --git a/config/locales/sc.yml b/config/locales/sc.yml index 306e670b7182ca..9ab62cea71e56b 100644 --- a/config/locales/sc.yml +++ b/config/locales/sc.yml @@ -30,17 +30,25 @@ sc: created_msg: As creadu una nota de moderatzione. destroyed_msg: As cantzelladu una nota de moderatzione. accounts: + add_email_domain_block: Bloca domìniu de posta eletrònica approve: Aprova approved_msg: Sa dimanda de registru de %{username} est istada aprovada are_you_sure: Seguru? avatar: Immàgine de profilu by_domain: Domìniu change_email: + changed_msg: Indiritzu eletrònicu de su contu modificadu! current_email: Indiritzu eletrònicu atuale label: Muda s'indiritzu eletrònicu new_email: Indiritzu eletrònicu nou submit: Muda s'indiritzu eletrònicu title: Muda s'indiritzu eletrònicu de %{username} + change_role: + changed_msg: Ruolu modificadu. + edit_roles: Gesti is ruolos de utente + label: Modifica su ruolu + no_role: Nissunu ruolu + title: Modifica su ruolu de %{username} confirm: Cunfirma confirmed: Cunfirmadu confirming: Cunfirmende @@ -91,6 +99,7 @@ sc: most_recent_ip: IP prus reghente no_account_selected: Perunu contu est istadu mudadu, dae chi non nd'as seletzionadu no_limits_imposed: Sena lìmites + no_role_assigned: Nissunu ruolu assignadu not_subscribed: Sena sutiscritzione pending: De revisionare perform_full_suspension: Suspèndidu @@ -108,12 +117,19 @@ sc: removed_header_msg: S'immàgine de intestatzione de %{username} est istada bogada resend_confirmation: already_confirmed: Custa persone est giai cunfirmada + send: Torra a imbiare su ligòngiu de cunfirmatzione + success: Ligòngiu de cunfirmatzione imbiadu. reset: Reseta reset_password: Reseta sa crae resubscribe: Torra a sutascrìere + role: Ruolu search: Chirca + search_same_email_domain: Àteras persones cun su pròpiu domìniu de posta search_same_ip: Àteras persones cun sa pròpiu IP security: Seguresa + security_measures: + only_password: Crae isceti + password_and_2fa: Crae e 2FA sensitive: Sensìbile sensitized: Marcadu comente sensìbile shared_inbox_url: URL de intrada cumpartzida @@ -129,6 +145,8 @@ sc: suspension_irreversible: Is datos de custu contu sunt istados cantzellados in manera irreversìbile. Podes bogare sa suspensione a su contu pro chi si potzat impreare, ma no at a recuperare datu perunu de is chi teniat in antis. suspension_reversible_hint_html: Su contu est istadu suspèndidu, e is datos ant a èssere cantzelladu de su totu su %{date}. Finas a tando, su contu si podet ripristinare sena efetu malu perunu. Si boles cantzellare totu is datos de su contu immediatamente ddu podes fàghere inoghe in bassu. title: Contos + unblock_email: Isbloca s'indiritzu de posta eletrònica + unblocked_email_msg: Posta eletrònica de %{username} isblocada unconfirmed_email: Posta eletrònica sena cunfirmare undo_sensitized: Boga sa marcadura comente sensìbile undo_silenced: Non pòngias a sa muda @@ -143,21 +161,31 @@ sc: whitelisted: Federatzione permìtida action_logs: action_types: + approve_user: Aprova s'utente assigned_to_self_report: Assigna s'informe + change_email_user: Muda s'indiritzu eletrònicu pro s'utente + change_role_user: Muda su ruolu de s'utente confirm_user: Cunfirma s'utente create_account_warning: Crea un'avisu create_announcement: Crea un'annùntziu + create_canonical_email_block: Crea unu blocu de posta eletrònica create_custom_emoji: Crea un'emoji personalizadu create_domain_allow: Crea unu domìniu permìtidu create_domain_block: Crea unu blocu de domìniu + create_email_domain_block: Crea unu blocu de domìniu de posta eletrònica create_ip_block: Crea una règula IP + create_unavailable_domain: Crea unu domìniu no a disponimentu + create_user_role: Crea unu ruolu demote_user: Degrada s'utente destroy_announcement: Cantzella s'annùntziu + destroy_canonical_email_block: Cantzella su blocu de posta eletrònica destroy_custom_emoji: Cantzella s'emoji personalizadu destroy_domain_allow: Cantzella su domìniu permìtidu destroy_domain_block: Cantzella su blocu de domìniu + destroy_email_domain_block: Cantzella su blocu de domìniu de posta eletrònica destroy_ip_block: Cantzella sa règula IP destroy_status: Cantzella s'istadu + destroy_unavailable_domain: Cantzella su domìniu no a disponimentu disable_2fa_user: Disativa 2FA disable_custom_emoji: Disativa s'emoji personalizadu disable_user: Disativa utente @@ -165,23 +193,33 @@ sc: enable_user: Ativa utente memorialize_account: Torra in unu contu de regordu promote_user: Promove utente + reject_user: Refuda s'utente remove_avatar_user: Cantzella immàgine de profilu reopen_report: Torra a abèrrere s'informe + resend_user: Torra a imbiare messàgiu eletrònicu de cunfirmatzione reset_password_user: Reseta sa crae resolve_report: Isorve s'informe sensitive_account: Marca is cuntenutos multimediales in su contu tuo comente sensìbiles silence_account: Pone custu contu a sa muda suspend_account: Suspende custu contu unassigned_report: Boga s'assignatzione de custu informe + unblock_email_account: Isbloca s'indiritzu de posta eletrònica unsensitive_account: Boga sa marcadura "sensìbiles" a is elementos multimediales in su contu tuo unsilence_account: Boga custu contu de is contos a sa muda unsuspend_account: Boga custu contu de is contos suspèndidos update_announcement: Atualiza s'annùntziu update_custom_emoji: Atualiza s'emoji personalizadu update_domain_block: Atualiza blocu de domìniu + update_ip_block: Atualiza sa règula IP + update_report: Atualiza s'informe update_status: Atualiza s'istadu + update_user_role: Atualiza su ruolu actions: + approve_user_html: "%{name} at aprovadu su registru de %{target}" assigned_to_self_report_html: "%{name} s'est auto-assignadu s'informe %{target}" + change_email_user_html: "%{name} at mudadu s'indiritzu de posta eletrònica de s'utente %{target}" + change_role_user_html: "%{name} at mudadu su ruolu de %{target}" + confirm_user_html: "%{name} at cunfirmadu s'indiritzu de posta eletrònica de s'utente %{target}" create_account_warning_html: "%{name} at imbiadu un'avisu a %{target}" create_announcement_html: "%{name} at creadu un'annùntziu nou %{target}" create_custom_emoji_html: "%{name} at carrigadu un'emoji nou %{target}" @@ -291,6 +329,8 @@ sc: confirm_suspension: cancel: Annulla confirm: Suspende + remove_all_data: Custu at a cantzellare totu su cuntenutu, elementos multimediales e datos de profilu pro is contos de custu domìniu dae su serbidore tuo. + stop_communication: Su serbidore tuo at a tzessare sa comunicatzione cun custos serbidores. title: Cunfirma su blocu de domìniu de %{domain} created_msg: Protzessende su blocu de domìniu destroyed_msg: Su blocu de domìniu est istadu iscontzadu @@ -361,9 +401,12 @@ sc: dashboard: instance_accounts_dimension: Contos prus sighidos instance_accounts_measure: contos sarvados + instance_languages_dimension: Limbas printzipales instance_reports_measure: informes a subra de àtere + instance_statuses_measure: publicatziones sarvadas delivery: all: Totus + unavailable: No a disponimentu delivery_available: Sa cunsigna est a disponimentu empty: Perunu domìniu agatadu. known_accounts: diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml index 9cc32457f7465f..523e9a5fccd3ad 100644 --- a/config/locales/simple_form.lv.yml +++ b/config/locales/simple_form.lv.yml @@ -86,6 +86,7 @@ lv: 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ē. + media_cache_retention_period: Informācijas nesēju datnes no ierakstiem, kurus ir veikuši attālie lietotāji, tiek kešoti šajā serverī. Kad ir iestatīta apstiprinoša vērtība, informācijas nesēji tiks izdzēsti pēc norādītā dienu skaita. Ja informācijas nesēju dati tiks pieprasīti pēc tam, kad tie tika izdzēsti, tie tiks atkārtoti lejupielādēti, ja avota saturs joprojām būs pieejams. Saišu priekšskatījuma karšu vaicājumu biežuma ierobežojumu dēļ ir ieteicams iestatīt šo vērtību vismaz 14 dienas vai saišu priekšskatījuma kartes netiks atjauninātas pēc pieprasījuma pirms tā laika. 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' diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 8076682ed46e12..399ecc061af0db 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -8,10 +8,10 @@ sk: title: Ohľadom accounts: followers: - few: Sledovateľov + few: Sledujúcich many: Sledovateľov one: Sledujúci - other: Sledovatelia + other: Sledujúci following: Nasledujem instance_actor_flash: Toto konto je virtuálny aktér, ktorý predstavuje samotný server, a nie konkrétneho používateľa. Používa sa na účely federácie a nemal by byť pozastavený. last_active: naposledy aktívny @@ -1167,7 +1167,7 @@ sk: dormant: Spiace follow_failure: Nemožno nasledovať niektoré z vybraných účtov. follow_selected_followers: Následuj označených sledovatelov - followers: Následovatelia + followers: Sledovatelia following: Nasledovaní invited: Pozvaný/á last_active: Naposledy aktívny diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 738263191150de..f1e09837054afc 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -1,7 +1,7 @@ --- tr: about: - about_mastodon_html: Mastodon ücretsiz ve açık kaynaklı bir sosyal ağdır. Merkezileştirilmemiş yapısı sayesinde diğer ticari sosyal platformların aksine iletişimininizin tek bir firmada tutulmasının/yönetilmesinin önüne geçer. Güvendiğiniz bir sunucuyu seçerek oradaki kişilerle etkileşimde bulunabilirsiniz. Herkes kendi Mastodon sunucusunu kurabilir ve sorunsuz bir şekilde Mastodon sosyal ağına dahil edebilir. + about_mastodon_html: Mastodon ücretsiz ve açık kaynaklı bir sosyal ağdır. Merkezi olmayan yapısı sayesinde diğer ticari sosyal platformların aksine iletişimininizin tek bir firmada tutulmasının/yönetilmesinin önüne geçer. Güvendiğiniz bir sunucuyu seçerek oradaki kişilerle etkileşimde bulunabilirsiniz. Herkes kendi Mastodon sunucusunu kurabilir ve sorunsuz bir şekilde Mastodon sosyal ağına dahil edebilir! contact_missing: Ayarlanmadı contact_unavailable: Bulunamadı hosted_on: Mastodon %{domain} üzerinde barındırılıyor diff --git a/config/navigation.rb b/config/navigation.rb index f5269d18ce39f3..2480e1741b64ba 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -30,18 +30,18 @@ n.item :filters, safe_join([material_symbol('filter_alt'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? && !self_destruct } n.item :statuses_cleanup, safe_join([material_symbol('history'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? && !self_destruct } - n.item :security, safe_join([material_symbol('lock'), t('settings.account')]), edit_user_registration_path do |s| - s.item :password, safe_join([material_symbol('lock'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes} + n.item :security, safe_join([material_symbol('account_circle'), t('settings.account')]), edit_user_registration_path do |s| + s.item :password, safe_join([material_symbol('lock'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{^/auth|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes} s.item :two_factor_authentication, safe_join([material_symbol('safety_check'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_path, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys} s.item :authorized_apps, safe_join([material_symbol('list_alt'), t('settings.authorized_apps')]), oauth_authorized_applications_path, if: -> { !self_destruct } end n.item :data, safe_join([material_symbol('cloud_sync'), t('settings.import_and_export')]), settings_export_path do |s| - s.item :import, safe_join([material_symbol('cloud_upload'), t('settings.import')]), settings_imports_path, if: -> { current_user.functional? && !self_destruct } + s.item :import, safe_join([material_symbol('cloud_upload'), t('settings.import')]), settings_imports_path, highlights_on: %r{/settings/imports}, if: -> { current_user.functional? && !self_destruct } s.item :export, safe_join([material_symbol('cloud_download'), t('settings.export')]), settings_export_path end - n.item :invites, safe_join([material_symbol('person_add'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? && !self_destruct } + n.item :user_invites, safe_join([material_symbol('person_add'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? && !self_destruct } n.item :development, safe_join([material_symbol('code'), t('settings.development')]), settings_applications_path, highlights_on: %r{/settings/applications}, if: -> { current_user.functional? && !self_destruct } n.item :trends, safe_join([material_symbol('trending_up'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) && !self_destruct } do |s| @@ -57,7 +57,9 @@ s.item :accounts, safe_join([material_symbol('groups'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|admin/account_moderation_notes|/admin/pending_accounts|/admin/users}, if: -> { current_user.can?(:manage_users) } s.item :tags, safe_join([material_symbol('tag'), t('admin.tags.title')]), admin_tags_path, highlights_on: %r{/admin/tags}, if: -> { current_user.can?(:manage_taxonomies) } s.item :invites, safe_join([material_symbol('person_add'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) } - s.item :instances, safe_join([material_symbol('cloud'), 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) } + s.item :instances, safe_join([material_symbol('cloud'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows|/admin/export_domain_blocks}, if: lambda { + current_user.can?(:manage_federation) + } s.item :email_domain_blocks, safe_join([material_symbol('mail'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_path, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.can?(:manage_blocks) } s.item :ip_blocks, safe_join([material_symbol('hide_source'), t('admin.ip_blocks.title')]), admin_ip_blocks_path, highlights_on: %r{/admin/ip_blocks}, if: -> { current_user.can?(:manage_blocks) } s.item :action_logs, safe_join([material_symbol('list'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) } diff --git a/config/routes.rb b/config/routes.rb index 79b374e4132602..b04ffe096cc0ce 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -68,7 +68,7 @@ def redirect_with_vary(path) scope path: '.well-known' do scope module: :well_known do get 'oauth-authorization-server', to: 'oauth_metadata#show', as: :oauth_metadata, defaults: { format: 'json' } - get 'host-meta', to: 'host_meta#show', as: :host_meta, defaults: { format: 'xml' } + get 'host-meta', to: 'host_meta#show', as: :host_meta get 'nodeinfo', to: 'node_info#index', as: :nodeinfo, defaults: { format: 'json' } get 'webfinger', to: 'webfinger#show', as: :webfinger end diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 78194f578980f8..334e806227cf1a 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -145,8 +145,10 @@ end resources :users, only: [] do - resource :two_factor_authentication, only: [:destroy], controller: 'users/two_factor_authentications' - resource :role, only: [:show, :update], controller: 'users/roles' + scope module: :users do + resource :two_factor_authentication, only: [:destroy] + resource :role, only: [:show, :update] + end end resources :custom_emojis, only: [:index, :new, :create] do diff --git a/db/migrate/.rubocop.yml b/db/migrate/.rubocop.yml index 4e23800dd14965..6f8b6cc60da42e 100644 --- a/db/migrate/.rubocop.yml +++ b/db/migrate/.rubocop.yml @@ -2,3 +2,8 @@ inherit_from: ../../.rubocop.yml Naming/VariableNumber: CheckSymbols: false + +# Enabled here as workaround for https://docs.rubocop.org/rubocop/configuration.html#path-relativity +Rails/CreateTableWithTimestamps: + Include: + - '*.rb' diff --git a/db/migrate/20170508230434_create_conversation_mutes.rb b/db/migrate/20170508230434_create_conversation_mutes.rb index 01122c45166a92..4beba9dfa32009 100644 --- a/db/migrate/20170508230434_create_conversation_mutes.rb +++ b/db/migrate/20170508230434_create_conversation_mutes.rb @@ -2,7 +2,7 @@ class CreateConversationMutes < ActiveRecord::Migration[5.0] def change - create_table :conversation_mutes do |t| + create_table :conversation_mutes do |t| # rubocop:disable Rails/CreateTableWithTimestamps t.integer :account_id, null: false t.bigint :conversation_id, null: false end diff --git a/db/migrate/20170823162448_create_status_pins.rb b/db/migrate/20170823162448_create_status_pins.rb index c8d3fab3a5128e..2cf3a85ca9de6b 100644 --- a/db/migrate/20170823162448_create_status_pins.rb +++ b/db/migrate/20170823162448_create_status_pins.rb @@ -2,7 +2,7 @@ class CreateStatusPins < ActiveRecord::Migration[5.1] def change - create_table :status_pins do |t| + create_table :status_pins do |t| # rubocop:disable Rails/CreateTableWithTimestamps t.belongs_to :account, foreign_key: { on_delete: :cascade }, null: false t.belongs_to :status, foreign_key: { on_delete: :cascade }, null: false end diff --git a/db/migrate/20171116161857_create_list_accounts.rb b/db/migrate/20171116161857_create_list_accounts.rb index ff9ab3faad89bc..b0371e4c884771 100644 --- a/db/migrate/20171116161857_create_list_accounts.rb +++ b/db/migrate/20171116161857_create_list_accounts.rb @@ -2,7 +2,7 @@ class CreateListAccounts < ActiveRecord::Migration[5.2] def change - create_table :list_accounts do |t| + create_table :list_accounts do |t| # rubocop:disable Rails/CreateTableWithTimestamps t.belongs_to :list, foreign_key: { on_delete: :cascade }, null: false t.belongs_to :account, foreign_key: { on_delete: :cascade }, null: false t.belongs_to :follow, foreign_key: { on_delete: :cascade }, null: false diff --git a/db/migrate/20180929222014_create_account_conversations.rb b/db/migrate/20180929222014_create_account_conversations.rb index 9386b86e7c9181..4e85e68d4771f5 100644 --- a/db/migrate/20180929222014_create_account_conversations.rb +++ b/db/migrate/20180929222014_create_account_conversations.rb @@ -2,7 +2,7 @@ class CreateAccountConversations < ActiveRecord::Migration[5.2] def change - create_table :account_conversations do |t| + create_table :account_conversations do |t| # rubocop:disable Rails/CreateTableWithTimestamps t.belongs_to :account, foreign_key: { on_delete: :cascade } t.belongs_to :conversation, foreign_key: { on_delete: :cascade } t.bigint :participant_account_ids, array: true, null: false, default: [] diff --git a/db/migrate/20181007025445_create_pghero_space_stats.rb b/db/migrate/20181007025445_create_pghero_space_stats.rb index ddaf4aef31c6f0..696b53d8d77518 100644 --- a/db/migrate/20181007025445_create_pghero_space_stats.rb +++ b/db/migrate/20181007025445_create_pghero_space_stats.rb @@ -2,7 +2,7 @@ class CreatePgheroSpaceStats < ActiveRecord::Migration[5.2] def change - create_table :pghero_space_stats do |t| + create_table :pghero_space_stats do |t| # rubocop:disable Rails/CreateTableWithTimestamps t.text :database t.text :schema t.text :relation diff --git a/db/migrate/20190103124649_create_scheduled_statuses.rb b/db/migrate/20190103124649_create_scheduled_statuses.rb index a66546187eed57..02b4916be86281 100644 --- a/db/migrate/20190103124649_create_scheduled_statuses.rb +++ b/db/migrate/20190103124649_create_scheduled_statuses.rb @@ -2,7 +2,7 @@ class CreateScheduledStatuses < ActiveRecord::Migration[5.2] def change - create_table :scheduled_statuses do |t| + create_table :scheduled_statuses do |t| # rubocop:disable Rails/CreateTableWithTimestamps t.belongs_to :account, foreign_key: { on_delete: :cascade } t.datetime :scheduled_at, index: true t.jsonb :params diff --git a/db/migrate/20220824233535_create_status_trends.rb b/db/migrate/20220824233535_create_status_trends.rb index 52dcbf8f38e9e5..e68e5b7c11aa5d 100644 --- a/db/migrate/20220824233535_create_status_trends.rb +++ b/db/migrate/20220824233535_create_status_trends.rb @@ -2,7 +2,7 @@ class CreateStatusTrends < ActiveRecord::Migration[6.1] def change - create_table :status_trends do |t| + create_table :status_trends do |t| # rubocop:disable Rails/CreateTableWithTimestamps t.references :status, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true } t.references :account, null: false, foreign_key: { on_delete: :cascade } t.float :score, null: false, default: 0 diff --git a/db/migrate/20221006061337_create_preview_card_trends.rb b/db/migrate/20221006061337_create_preview_card_trends.rb index 934a06e24d1728..266f6440239751 100644 --- a/db/migrate/20221006061337_create_preview_card_trends.rb +++ b/db/migrate/20221006061337_create_preview_card_trends.rb @@ -2,7 +2,7 @@ class CreatePreviewCardTrends < ActiveRecord::Migration[6.1] def change - create_table :preview_card_trends do |t| + create_table :preview_card_trends do |t| # rubocop:disable Rails/CreateTableWithTimestamps t.references :preview_card, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true } t.float :score, null: false, default: 0 t.integer :rank, null: false, default: 0 diff --git a/lib/mastodon/cli/media.rb b/lib/mastodon/cli/media.rb index 70c11ee1a15b94..996b7fd92ca3b6 100644 --- a/lib/mastodon/cli/media.rb +++ b/lib/mastodon/cli/media.rb @@ -177,7 +177,7 @@ def remove_orphans attachment_name = path_segments[1].singularize file_name = path_segments.last - next unless PRELOAD_MODEL_WHITELIST.include?(model_name) + next unless PRELOADED_MODELS.include?(model_name) record = model_name.constantize.find_by(id: record_id) attachment = record&.public_send(attachment_name) @@ -278,14 +278,10 @@ def refresh desc 'usage', 'Calculate disk space consumed by Mastodon' def usage - say("Attachments:\t#{number_to_human_size(media_attachment_storage_size)} (#{number_to_human_size(local_media_attachment_storage_size)} local)") - say("Custom emoji:\t#{number_to_human_size(CustomEmoji.sum(:image_file_size))} (#{number_to_human_size(CustomEmoji.local.sum(:image_file_size))} local)") - say("Preview cards:\t#{number_to_human_size(PreviewCard.sum(:image_file_size))}") - say("Avatars:\t#{number_to_human_size(Account.sum(:avatar_file_size))} (#{number_to_human_size(Account.local.sum(:avatar_file_size))} local)") - say("Headers:\t#{number_to_human_size(Account.sum(:header_file_size))} (#{number_to_human_size(Account.local.sum(:header_file_size))} local)") - say("Backups:\t#{number_to_human_size(Backup.sum(:dump_file_size))}") - say("Imports:\t#{number_to_human_size(Import.sum(:data_file_size))}") - say("Settings:\t#{number_to_human_size(SiteUpload.sum(:file_file_size))}") + print_table [ + %w(Object Total Local), + *object_storage_summary, + ] end desc 'lookup URL', 'Lookup where media is displayed by passing a media URL' @@ -300,7 +296,7 @@ def lookup(url) model_name = path_segments.first.classify 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) + fail_with_message "Cannot find corresponding model: #{model_name}" unless PRELOADED_MODELS.include?(model_name) record = model_name.constantize.find_by(id: record_id) record = record.status if record.respond_to?(:status) @@ -318,23 +314,26 @@ def lookup(url) private - def media_attachment_storage_size - MediaAttachment.sum(file_and_thumbnail_size_sql) + def object_storage_summary + [ + [:attachments, MediaAttachment.sum(combined_media_sum), MediaAttachment.where(account: Account.local).sum(combined_media_sum)], + [:custom_emoji, CustomEmoji.sum(:image_file_size), CustomEmoji.local.sum(:image_file_size)], + [:avatars, Account.sum(:avatar_file_size), Account.local.sum(:avatar_file_size)], + [:headers, Account.sum(:header_file_size), Account.local.sum(:header_file_size)], + [:preview_cards, PreviewCard.sum(:image_file_size), nil], + [:backups, Backup.sum(:dump_file_size), nil], + [:imports, Import.sum(:data_file_size), nil], + [:settings, SiteUpload.sum(:file_file_size), nil], + ].map { |label, total, local| [label.to_s.titleize, number_to_human_size(total), local.present? ? number_to_human_size(local) : nil] } end - def local_media_attachment_storage_size - MediaAttachment.where(account: Account.local).sum(file_and_thumbnail_size_sql) + def combined_media_sum + Arel.sql(<<~SQL.squish) + COALESCE(file_file_size, 0) + COALESCE(thumbnail_file_size, 0) + SQL end - def file_and_thumbnail_size_sql - Arel.sql( - <<~SQL.squish - COALESCE(file_file_size, 0) + COALESCE(thumbnail_file_size, 0) - SQL - ) - end - - PRELOAD_MODEL_WHITELIST = %w( + PRELOADED_MODELS = %w( Account Backup CustomEmoji @@ -356,7 +355,7 @@ def preload_records_from_mixed_objects(objects) model_name = segments.first.classify record_id = segments[2...-2].join.to_i - next unless PRELOAD_MODEL_WHITELIST.include?(model_name) + next unless PRELOADED_MODELS.include?(model_name) preload_map[model_name] << record_id end diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 0cc6ee3f8973d3..5bc32b1eaf605d 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -9,7 +9,7 @@ def major end def minor - 3 + 4 end def patch @@ -17,7 +17,7 @@ def patch end def default_prerelease - 'rc.1' + 'alpha.1' end def prerelease diff --git a/lib/sanitize_ext/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb index ed244d4a3ef44f..2b7cb10321a77e 100644 --- a/lib/sanitize_ext/sanitize_config.rb +++ b/lib/sanitize_ext/sanitize_config.rb @@ -21,7 +21,7 @@ module Config gemini ).freeze - CLASS_WHITELIST_TRANSFORMER = lambda do |env| + ALLOWED_CLASS_TRANSFORMER = lambda do |env| node = env[:node] class_list = node['class']&.split(/[\t\n\f\r ]/) @@ -99,7 +99,7 @@ module Config }, transformers: [ - CLASS_WHITELIST_TRANSFORMER, + ALLOWED_CLASS_TRANSFORMER, IMG_TAG_TRANSFORMER, TRANSLATE_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, @@ -163,7 +163,7 @@ module Config add_attributes: {}, transformers: [ - CLASS_WHITELIST_TRANSFORMER, + ALLOWED_CLASS_TRANSFORMER, IMG_TAG_TRANSFORMER, TRANSLATE_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, diff --git a/lib/tasks/icons.rake b/lib/tasks/icons.rake index 96e0a143150584..9a05cf349914d2 100644 --- a/lib/tasks/icons.rake +++ b/lib/tasks/icons.rake @@ -38,6 +38,20 @@ def find_used_icons end end + Rails.root.join('config', 'navigation.rb').open('r') do |file| + pattern = /material_symbol\('(?[^']*)'\)/ + file.each_line do |line| + match = pattern.match(line) + next if match.blank? + + # navigation.rb only uses 400x24 icons, per material_symbol() in + # app/helpers/application_helper.rb + icons_by_weight_and_size[400] ||= {} + icons_by_weight_and_size[400][24] ||= Set.new + icons_by_weight_and_size[400][24] << match['icon'] + end + end + icons_by_weight_and_size end diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb index 713ea3ff16c5bf..4a6956cb095e1c 100644 --- a/spec/controllers/auth/sessions_controller_spec.rb +++ b/spec/controllers/auth/sessions_controller_spec.rb @@ -208,7 +208,7 @@ context 'when using two-factor authentication' do context 'with OTP enabled as second factor' do let!(:user) do - Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32)) + Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret) end let!(:recovery_codes) do @@ -230,7 +230,7 @@ context 'when using email and password after an unfinished log-in attempt to a 2FA-protected account' do let!(:other_user) do - Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32)) + Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret) end before do @@ -342,7 +342,7 @@ context 'with WebAuthn and OTP enabled as second factor' do let!(:user) do - Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32)) + Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret) end let!(:webauthn_credential) do diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb index 34eaacdf498f96..224310b7ef3043 100644 --- a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb @@ -18,7 +18,7 @@ def qr_code_markup RQRCode::QRCode.new( 'otpauth://totp/cb6e6126.ngrok.io:local-part%40domain?secret=thisisasecretforthespecofnewview&issuer=cb6e6126.ngrok.io' - ).as_svg(padding: 0, module_size: 4) + ).as_svg(padding: 0, module_size: 4, use_path: true) end end diff --git a/spec/fabricators/account_domain_block_fabricator.rb b/spec/fabricators/account_domain_block_fabricator.rb index 83df509da2cc85..a211b7c6667031 100644 --- a/spec/fabricators/account_domain_block_fabricator.rb +++ b/spec/fabricators/account_domain_block_fabricator.rb @@ -2,5 +2,5 @@ Fabricator(:account_domain_block) do account { Fabricate.build(:account) } - domain 'example.com' + domain { sequence { |n| "host-#{n}.example" } } end diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 83ea6566e41402..ab69a4693db6c5 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -63,6 +63,24 @@ } end + let(:invalid_mention_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), 'post2'].join('/'), + type: 'Note', + to: [ + 'https://www.w3.org/ns/activitystreams#Public', + ActivityPub::TagManager.instance.uri_for(follower), + ], + content: '@bob lorem ipsum', + published: 1.hour.ago.utc.iso8601, + updated: 1.hour.ago.utc.iso8601, + tag: { + type: 'Mention', + href: 'http://notexisting.dontexistingtld/actor', + }, + } + end + def activity_for_object(json) { '@context': 'https://www.w3.org/ns/activitystreams', @@ -117,6 +135,25 @@ def activity_for_object(json) # Creates two notifications expect(Notification.count).to eq 2 end + + it 'ignores unprocessable mention', :aggregate_failures do + stub_request(:get, invalid_mention_json[:tag][:href]).to_raise(HTTP::ConnectionError) + # When receiving the post that contains an invalid mention… + described_class.new(activity_for_object(invalid_mention_json), sender, delivery: true).perform + + # NOTE: Refering explicitly to the workers is a bit awkward + DistributionWorker.drain + FeedInsertWorker.drain + + # …it creates a status + status = Status.find_by(uri: invalid_mention_json[:id]) + + # Check the process did not crash + expect(status.nil?).to be false + + # It has queued a mention resolve job + expect(MentionResolveWorker).to have_enqueued_sidekiq_job(status.id, invalid_mention_json[:tag][:href], anything) + end end describe '#perform' do diff --git a/spec/mailers/notification_mailer_spec.rb b/spec/mailers/notification_mailer_spec.rb index 4c6107d9f76fce..d97c01858da6b9 100644 --- a/spec/mailers/notification_mailer_spec.rb +++ b/spec/mailers/notification_mailer_spec.rb @@ -14,6 +14,17 @@ end end + shared_examples 'delivery without status' do + context 'when notification target_status is missing' do + before { allow(notification).to receive(:target_status).and_return(nil) } + + it 'does not deliver mail' do + emails = capture_emails { mail.deliver_now } + expect(emails).to be_empty + end + end + end + let(:receiver) { Fabricate(:user, account_attributes: { username: 'alice' }) } let(:sender) { Fabricate(:account, username: 'bob') } let(:foreign_status) { Fabricate(:status, account: sender, text: 'The body of the foreign status') } @@ -37,6 +48,7 @@ end include_examples 'delivery to non functional user' + include_examples 'delivery without status' end describe 'follow' do @@ -75,6 +87,7 @@ end include_examples 'delivery to non functional user' + include_examples 'delivery without status' end describe 'reblog' do @@ -95,6 +108,7 @@ end include_examples 'delivery to non functional user' + include_examples 'delivery without status' end describe 'follow_request' do diff --git a/spec/models/export_spec.rb b/spec/models/export_spec.rb index 06bf07ed78a314..81aaf8858556fe 100644 --- a/spec/models/export_spec.rb +++ b/spec/models/export_spec.rb @@ -3,66 +3,104 @@ require 'rails_helper' RSpec.describe Export do + subject { described_class.new(account) } + let(:account) { Fabricate(:account) } let(:target_accounts) do - [{}, { username: 'one', domain: 'local.host' }].map(&method(:Fabricate).curry(2).call(:account)) + [ + Fabricate(:account), + Fabricate(:account, username: 'one', domain: 'local.host'), + ] end - describe 'to_csv' do - it 'returns a csv of the blocked accounts' do - target_accounts.each { |target_account| account.block!(target_account) } + describe '#to_bookmarks_csv' do + before { Fabricate.times(2, :bookmark, account: account) } - export = described_class.new(account).to_blocked_accounts_csv - results = export.strip.split + let(:export) { CSV.parse(subject.to_bookmarks_csv) } - expect(results.size).to eq 2 - expect(results.first).to eq 'one@local.host' + it 'returns a csv of bookmarks' do + expect(export) + .to contain_exactly( + include(/statuses/), + include(/statuses/) + ) end + end - it 'returns a csv of the muted accounts' do - target_accounts.each { |target_account| account.mute!(target_account) } + describe '#to_blocked_accounts_csv' do + before { target_accounts.each { |target_account| account.block!(target_account) } } - export = described_class.new(account).to_muted_accounts_csv - results = export.strip.split("\n") + let(:export) { CSV.parse(subject.to_blocked_accounts_csv) } - expect(results.size).to eq 3 - expect(results.first).to eq 'Account address,Hide notifications' - expect(results.second).to eq 'one@local.host,true' + it 'returns a csv of the blocked accounts' do + expect(export) + .to contain_exactly( + include('one@local.host'), + include(be_present) + ) end + end - it 'returns a csv of the following accounts' do - target_accounts.each { |target_account| account.follow!(target_account) } + describe '#to_muted_accounts_csv' do + before { target_accounts.each { |target_account| account.mute!(target_account) } } - export = described_class.new(account).to_following_accounts_csv - results = export.strip.split("\n") + let(:export) { CSV.parse(subject.to_muted_accounts_csv) } - expect(results.size).to eq 3 - expect(results.first).to eq 'Account address,Show boosts,Notify on new posts,Languages' - expect(results.second).to eq 'one@local.host,true,false,' + it 'returns a csv of the muted accounts' do + expect(export) + .to contain_exactly( + contain_exactly('Account address', 'Hide notifications'), + include('one@local.host', 'true'), + include(be_present) + ) end end - describe 'total_storage' do - it 'returns the total size of the media attachments' do - media_attachment = Fabricate(:media_attachment, account: account) - expect(described_class.new(account).total_storage).to eq media_attachment.file_file_size || 0 + describe '#to_following_accounts_csv' do + before { target_accounts.each { |target_account| account.follow!(target_account) } } + + let(:export) { CSV.parse(subject.to_following_accounts_csv) } + + it 'returns a csv of the following accounts' do + expect(export) + .to contain_exactly( + contain_exactly('Account address', 'Show boosts', 'Notify on new posts', 'Languages'), + include('one@local.host', 'true', 'false', be_blank), + include(be_present) + ) end end - describe 'total_follows' do - it 'returns the total number of the followed accounts' do - target_accounts.each { |target_account| account.follow!(target_account) } - expect(described_class.new(account.reload).total_follows).to eq 2 + describe '#to_lists_csv' do + before do + target_accounts.each do |target_account| + account.follow!(target_account) + Fabricate(:list, account: account).accounts << target_account + end end - it 'returns the total number of the blocked accounts' do - target_accounts.each { |target_account| account.block!(target_account) } - expect(described_class.new(account.reload).total_blocks).to eq 2 + let(:export) { CSV.parse(subject.to_lists_csv) } + + it 'returns a csv of the lists' do + expect(export) + .to contain_exactly( + include('one@local.host'), + include(be_present) + ) end + end + + describe '#to_blocked_domains_csv' do + before { Fabricate.times(2, :account_domain_block, account: account) } + + let(:export) { CSV.parse(subject.to_blocked_domains_csv) } - it 'returns the total number of the muted accounts' do - target_accounts.each { |target_account| account.mute!(target_account) } - expect(described_class.new(account.reload).total_mutes).to eq 2 + it 'returns a csv of the blocked domains' do + expect(export) + .to contain_exactly( + include(/example/), + include(/example/) + ) end end end diff --git a/spec/models/report_filter_spec.rb b/spec/models/report_filter_spec.rb index 8668eb3d1085e8..51933e475adb70 100644 --- a/spec/models/report_filter_spec.rb +++ b/spec/models/report_filter_spec.rb @@ -30,4 +30,17 @@ expect(Report).to have_received(:resolved) end end + + context 'when given remote target_origin and also by_target_domain' do + let!(:matching_report) { Fabricate :report, target_account: Fabricate(:account, domain: 'match.example') } + let!(:non_matching_report) { Fabricate :report, target_account: Fabricate(:account, domain: 'other.example') } + + it 'preserves the domain value' do + filter = described_class.new(by_target_domain: 'match.example', target_origin: 'remote') + + expect(filter.results) + .to include(matching_report) + .and not_include(non_matching_report) + end + end end diff --git a/spec/presenters/export_summary_spec.rb b/spec/presenters/export_summary_spec.rb new file mode 100644 index 00000000000000..0ed46c857d5fee --- /dev/null +++ b/spec/presenters/export_summary_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ExportSummary do + subject { described_class.new(account) } + + let(:account) { Fabricate(:account) } + let(:target_accounts) do + [ + Fabricate(:account), + Fabricate(:account, username: 'one', domain: 'local.host'), + ] + end + + describe '#total_storage' do + it 'returns the total size of the media attachments' do + media_attachment = Fabricate(:media_attachment, account: account) + expect(subject.total_storage).to eq media_attachment.file_file_size || 0 + end + end + + describe '#total_statuses' do + before { Fabricate.times(2, :status, account: account) } + + it 'returns the total number of statuses' do + expect(subject.total_statuses).to eq(2) + end + end + + describe '#total_bookmarks' do + before { Fabricate.times(2, :bookmark, account: account) } + + it 'returns the total number of bookmarks' do + expect(subject.total_bookmarks).to eq(2) + end + end + + describe '#total_follows' do + before { target_accounts.each { |target_account| account.follow!(target_account) } } + + it 'returns the total number of the followed accounts' do + expect(subject.total_follows).to eq(2) + end + end + + describe '#total_lists' do + before { Fabricate.times(2, :list, account: account) } + + it 'returns the total number of lists' do + expect(subject.total_lists).to eq(2) + end + end + + describe '#total_followers' do + before { target_accounts.each { |target_account| target_account.follow!(account) } } + + it 'returns the total number of the follower accounts' do + expect(subject.total_followers).to eq(2) + end + end + + describe '#total_blocks' do + before { target_accounts.each { |target_account| account.block!(target_account) } } + + it 'returns the total number of the blocked accounts' do + expect(subject.total_blocks).to eq(2) + end + end + + describe '#total_mutes' do + before { target_accounts.each { |target_account| account.mute!(target_account) } } + + it 'returns the total number of the muted accounts' do + expect(subject.total_mutes).to eq(2) + end + end + + describe '#total_domain_blocks' do + before { Fabricate.times(2, :account_domain_block, account: account) } + + it 'returns the total number of account domain blocks' do + expect(subject.total_domain_blocks).to eq(2) + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index ee03b49bc6aa16..84cee0974f1a42 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -161,6 +161,11 @@ def sign_in(resource, _deprecated = nil, scope: nil) host! Rails.configuration.x.local_domain end + config.before :each, type: :system do + # Align with capybara config so that rails helpers called from rspec use matching host + host! 'localhost:3000' + end + config.after do Rails.cache.clear redis.del(redis.keys) diff --git a/spec/requests/auth/sessions/security_key_options_spec.rb b/spec/requests/auth/sessions/security_key_options_spec.rb index 6246e4beb315f7..e53b9802b4c820 100644 --- a/spec/requests/auth/sessions/security_key_options_spec.rb +++ b/spec/requests/auth/sessions/security_key_options_spec.rb @@ -6,7 +6,7 @@ RSpec.describe 'Security Key Options' do describe 'GET /auth/sessions/security_key_options' do let!(:user) do - Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32)) + Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret) end context 'with WebAuthn and OTP enabled as second factor' do diff --git a/spec/requests/well_known/host_meta_spec.rb b/spec/requests/well_known/host_meta_spec.rb index 09f17baa894d64..8d8e38f5217243 100644 --- a/spec/requests/well_known/host_meta_spec.rb +++ b/spec/requests/well_known/host_meta_spec.rb @@ -3,25 +3,62 @@ require 'rails_helper' RSpec.describe 'The /.well-known/host-meta request' do - it 'returns http success with valid XML response' do - get '/.well-known/host-meta' - - expect(response) - .to have_http_status(200) - .and have_attributes( - media_type: 'application/xrd+xml', - body: host_meta_xml_template - ) + context 'without extension format or accept header' do + it 'returns http success with expected XML' do + get '/.well-known/host-meta' + + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: 'application/xrd+xml' + ) + + expect(xrd_link_template_value) + .to eq 'https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}' + end + + def xrd_link_template_value + response + .parsed_body + .at_xpath('/xrd:XRD/xrd:Link[@rel="lrdd"]/@template', 'xrd' => 'http://docs.oasis-open.org/ns/xri/xrd-1.0') + .value + end + end + + context 'with a .json format extension' do + it 'returns http success with expected JSON' do + get '/.well-known/host-meta.json' + + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: 'application/json' + ) + expect(response.parsed_body) + .to include(expected_json_template) + end end - private + context 'with a JSON `Accept` header' do + it 'returns http success with expected JSON' do + get '/.well-known/host-meta', headers: { 'Accept' => 'application/json' } + + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: 'application/json' + ) + expect(response.parsed_body) + .to include(expected_json_template) + end + end - def host_meta_xml_template - <<~XML - - - - - XML + def expected_json_template + { + links: [ + 'rel' => 'lrdd', + 'template' => 'https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}', + ], + } end end diff --git a/spec/routing/well_known_routes_spec.rb b/spec/routing/well_known_routes_spec.rb index 6578e939ae1e14..84081059bba75e 100644 --- a/spec/routing/well_known_routes_spec.rb +++ b/spec/routing/well_known_routes_spec.rb @@ -4,9 +4,14 @@ RSpec.describe 'Well Known routes' do describe 'the host-meta route' do - it 'routes to correct place with xml format' do + it 'routes to correct place' do expect(get('/.well-known/host-meta')) - .to route_to('well_known/host_meta#show', format: 'xml') + .to route_to('well_known/host_meta#show') + end + + it 'routes to correct place with json format' do + expect(get('/.well-known/host-meta.json')) + .to route_to('well_known/host_meta#show', format: 'json') end end diff --git a/spec/services/account_statuses_cleanup_service_spec.rb b/spec/services/account_statuses_cleanup_service_spec.rb index 857bd4fda499af..553d20029a6624 100644 --- a/spec/services/account_statuses_cleanup_service_spec.rb +++ b/spec/services/account_statuses_cleanup_service_spec.rb @@ -27,39 +27,35 @@ end context 'when given a normal budget of 10' do - it 'reports 3 deleted statuses' do - expect(subject.call(account_policy, 10)).to eq 3 - end - - it 'records the last deleted id' do - subject.call(account_policy, 10) - expect(account_policy.last_inspected).to eq [old_status.id, another_old_status.id].max - end - - it 'actually deletes the statuses' do - subject.call(account_policy, 10) - expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil - expect { recent_status.reload }.to_not raise_error - end - - it 'preserves recent and unrelated statuses' do - subject.call(account_policy, 10) - expect { unrelated_status.reload }.to_not raise_error - expect { recent_status.reload }.to_not raise_error + it 'reports 3 deleted statuses and records last deleted id, deletes statuses, preserves recent unrelated statuses' do + expect(subject.call(account_policy, 10)) + .to eq(3) + + expect(account_policy.last_inspected) + .to eq [old_status.id, another_old_status.id].max + + expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])) + .to be_nil + expect { recent_status.reload } + .to_not raise_error + expect { unrelated_status.reload } + .to_not raise_error + expect { recent_status.reload } + .to_not raise_error end end context 'when called repeatedly with a budget of 2' do - it 'reports 2 then 1 deleted statuses' do - expect(subject.call(account_policy, 2)).to eq 2 - expect(subject.call(account_policy, 2)).to eq 1 - end - - it 'actually deletes the statuses in the expected order' do - subject.call(account_policy, 2) - expect(Status.find_by(id: very_old_status.id)).to be_nil - subject.call(account_policy, 2) - expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil + it 'reports 2 then 1 deleted statuses and deletes in expected order' do + expect(subject.call(account_policy, 2)) + .to eq(2) + expect(Status.find_by(id: very_old_status.id)) + .to be_nil + + expect(subject.call(account_policy, 2)) + .to eq(1) + expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])) + .to be_nil end end @@ -90,19 +86,24 @@ end end - it 'reports 0 deleted statuses then 0 then 3 then 0 again' do - expect(subject.call(account_policy, 10)).to eq 0 - expect(subject.call(account_policy, 10)).to eq 0 - expect(subject.call(account_policy, 10)).to eq 3 - expect(subject.call(account_policy, 10)).to eq 0 + it 'reports 0 deleted statuses then 0 then 3 then 0 again, and keeps id under oldest deletable record' do + expect(subject.call(account_policy, 10)) + .to eq(0) + expect(subject.call(account_policy, 10)) + .to eq(0) + expect(subject.call(account_policy, 10)) + .to eq(3) + expect(subject.call(account_policy, 10)) + .to eq(0) + expect(account_policy.last_inspected) + .to be < oldest_deletable_record_id end - it 'never causes the recorded id to get higher than oldest deletable toot' do - subject.call(account_policy, 10) - subject.call(account_policy, 10) - subject.call(account_policy, 10) - subject.call(account_policy, 10) - expect(account_policy.last_inspected).to be < Mastodon::Snowflake.id_at(account_policy.min_status_age.seconds.ago, with_random: false) + def oldest_deletable_record_id + Mastodon::Snowflake.id_at( + account_policy.min_status_age.seconds.ago, + with_random: false + ) end end end diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index a97e8408026b7c..b6ceba374f7825 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -2,10 +2,6 @@ require 'rails_helper' -def poll_option_json(name, votes) - { type: 'Note', name: name, replies: { type: 'Collection', totalItems: votes } } -end - RSpec.describe ActivityPub::ProcessStatusUpdateService do subject { described_class.new } @@ -294,7 +290,6 @@ def poll_option_json(name, votes) context 'when originally without media attachments' do before do stub_request(:get, 'https://example.com/foo.png').to_return(body: attachment_fixture('emojo.png')) - subject.call(status, json, json) end let(:payload) do @@ -310,19 +305,18 @@ def poll_option_json(name, votes) } end - it 'updates media attachments' do - media_attachment = status.reload.ordered_media_attachments.first + it 'updates media attachments, fetches attachment, records media change in edit' do + subject.call(status, json, json) - expect(media_attachment).to_not be_nil - expect(media_attachment.remote_url).to eq 'https://example.com/foo.png' - end + expect(status.reload.ordered_media_attachments.first) + .to be_present + .and(have_attributes(remote_url: 'https://example.com/foo.png')) - it 'fetches the attachment' do - expect(a_request(:get, 'https://example.com/foo.png')).to have_been_made - end + expect(a_request(:get, 'https://example.com/foo.png')) + .to have_been_made - it 'records media change in edit' do - expect(status.edits.reload.last.ordered_media_attachment_ids).to_not be_empty + expect(status.edits.reload.last.ordered_media_attachment_ids) + .to_not be_empty end end @@ -344,27 +338,26 @@ def poll_option_json(name, votes) before do allow(RedownloadMediaWorker).to receive(:perform_async) - subject.call(status, json, json) end - it 'updates the existing media attachment in-place' do - media_attachment = status.media_attachments.ordered.reload.first + it 'updates the existing media attachment in-place, does not queue redownload, updates media, records media change' do + subject.call(status, json, json) - expect(media_attachment).to_not be_nil - expect(media_attachment.remote_url).to eq 'https://example.com/foo.png' - expect(media_attachment.description).to eq 'A picture' - end + expect(status.media_attachments.ordered.reload.first) + .to be_present + .and have_attributes( + remote_url: 'https://example.com/foo.png', + description: 'A picture' + ) - it 'does not queue redownload for the existing media attachment' do - expect(RedownloadMediaWorker).to_not have_received(:perform_async) - end + expect(RedownloadMediaWorker) + .to_not have_received(:perform_async) - it 'updates media attachments' do - expect(status.ordered_media_attachments.map(&:remote_url)).to eq %w(https://example.com/foo.png) - end + expect(status.ordered_media_attachments.map(&:remote_url)) + .to eq %w(https://example.com/foo.png) - it 'records media change in edit' do - expect(status.edits.reload.last.ordered_media_attachment_ids).to_not be_empty + expect(status.edits.reload.last.ordered_media_attachment_ids) + .to_not be_empty end end @@ -372,10 +365,11 @@ def poll_option_json(name, votes) before do poll = Fabricate(:poll, status: status) status.update(preloadable_poll: poll) - subject.call(status, json, json) end it 'removes poll and records media change in edit' do + subject.call(status, json, json) + expect(status.reload.poll).to be_nil expect(status.edits.reload.last.poll_options).to be_nil end @@ -398,15 +392,13 @@ def poll_option_json(name, votes) } end - before do + it 'creates a poll and records media change in edit' do subject.call(status, json, json) - end - it 'creates a poll and records media change in edit' do - poll = status.reload.poll + expect(status.reload.poll) + .to be_present + .and have_attributes(options: %w(Foo Bar Baz)) - expect(poll).to_not be_nil - expect(poll.options).to eq %w(Foo Bar Baz) expect(status.edits.reload.last.poll_options).to eq %w(Foo Bar Baz) end end @@ -419,4 +411,8 @@ def poll_option_json(name, votes) .to eq '2021-09-08 22:39:25 UTC' end end + + def poll_option_json(name, votes) + { type: 'Note', name: name, replies: { type: 'Collection', totalItems: votes } } + end end diff --git a/spec/services/authorize_follow_service_spec.rb b/spec/services/authorize_follow_service_spec.rb index 533b791fb7f6e7..de2857280249cb 100644 --- a/spec/services/authorize_follow_service_spec.rb +++ b/spec/services/authorize_follow_service_spec.rb @@ -12,15 +12,15 @@ before do FollowRequest.create(account: bob, target_account: sender) - subject.call(bob, sender) end - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end + it 'removes follow request and creates follow relation' do + subject.call(bob, sender) - it 'creates follow relation' do - expect(bob.following?(sender)).to be true + expect(bob) + .to_not be_requested(sender) + expect(bob) + .to be_following(sender) end end @@ -30,19 +30,17 @@ before do FollowRequest.create(account: bob, target_account: sender) stub_request(:post, bob.inbox_url).to_return(status: 200) - subject.call(bob, sender) end - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end - - it 'creates follow relation' do - expect(bob.following?(sender)).to be true - end + it 'removes follow request, creates follow relation, send accept activity', :inline_jobs do + subject.call(bob, sender) - it 'sends an accept activity', :inline_jobs do - expect(a_request(:post, bob.inbox_url)).to have_been_made.once + expect(bob) + .to_not be_requested(sender) + expect(bob) + .to be_following(sender) + expect(a_request(:post, bob.inbox_url)) + .to have_been_made.once end end end diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb index 628bb198ef06f3..1ff73a633b1002 100644 --- a/spec/services/batched_remove_status_service_spec.rb +++ b/spec/services/batched_remove_status_service_spec.rb @@ -24,32 +24,38 @@ status_alice_hello status_alice_other + end + it 'removes status records, removes from author and local follower feeds, notifies stream, sends delete' do subject.call([status_alice_hello, status_alice_other]) - end - it 'removes statuses' do - expect { Status.find(status_alice_hello.id) }.to raise_error ActiveRecord::RecordNotFound - expect { Status.find(status_alice_other.id) }.to raise_error ActiveRecord::RecordNotFound - end + expect { Status.find(status_alice_hello.id) } + .to raise_error ActiveRecord::RecordNotFound + expect { Status.find(status_alice_other.id) } + .to raise_error ActiveRecord::RecordNotFound - it 'removes statuses from author\'s home feed' do - expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id) - end + expect(feed_ids_for(alice)) + .to_not include(status_alice_hello.id, status_alice_other.id) - it 'removes statuses from local follower\'s home feed' do - expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id) - end + expect(feed_ids_for(jeff)) + .to_not include(status_alice_hello.id, status_alice_other.id) - it 'notifies streaming API of followers' do - expect(redis).to have_received(:publish).with("timeline:#{jeff.id}", any_args).at_least(:once) - end + expect(redis) + .to have_received(:publish) + .with("timeline:#{jeff.id}", any_args).at_least(:once) + + expect(redis) + .to have_received(:publish) + .with('timeline:public', any_args).at_least(:once) - it 'notifies streaming API of public timeline' do - expect(redis).to have_received(:publish).with('timeline:public', any_args).at_least(:once) + expect(a_request(:post, 'http://example.com/inbox')) + .to have_been_made.at_least_once end - it 'sends delete activity to followers' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once + def feed_ids_for(account) + HomeFeed + .new(account) + .get(10) + .pluck(:id) end end diff --git a/spec/services/block_service_spec.rb b/spec/services/block_service_spec.rb index 46dd69198699a4..d9687a5404dc0a 100644 --- a/spec/services/block_service_spec.rb +++ b/spec/services/block_service_spec.rb @@ -26,15 +26,16 @@ before do stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - subject.call(sender, bob) end - it 'creates a blocking relation' do - expect(sender.blocking?(bob)).to be true - end + it 'creates a blocking relation and send block activity', :inline_jobs do + subject.call(sender, bob) + + expect(sender) + .to be_blocking(bob) - it 'sends a block activity', :inline_jobs do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once + expect(a_request(:post, 'http://example.com/inbox')) + .to have_been_made.once end end end diff --git a/spec/services/bulk_import_service_spec.rb b/spec/services/bulk_import_service_spec.rb index 0197f81a448dd7..f52fc4d7d5e83a 100644 --- a/spec/services/bulk_import_service_spec.rb +++ b/spec/services/bulk_import_service_spec.rb @@ -24,30 +24,19 @@ ].map { |data| import.rows.create!(data: data) } end - before do - account.follow!(Fabricate(:account)) - end - - it 'does not immediately change who the account follows' do - expect { subject.call(import) }.to_not(change { account.reload.active_relationships.to_a }) - end + before { account.follow!(Fabricate(:account)) } - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end - - it 'requests to follow all the listed users once the workers have run' do - subject.call(import) + it 'does not immediately change who the account follows, enqueues workers, sends follow requests after worker run' do + expect { subject.call(import) } + .to_not(change { account.reload.active_relationships.to_a }) - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } + expect(row_worker_job_args) + .to match_array(rows.map(&:id)) - Import::RowWorker.drain + stub_resolve_account_and_drain_workers - expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }).to contain_exactly('user@foo.bar', 'unknown@unknown.bar') + expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }) + .to contain_exactly('user@foo.bar', 'unknown@unknown.bar') end end @@ -71,31 +60,20 @@ account.follow!(to_be_unfollowed) end - it 'unfollows user not present on list' do - subject.call(import) - expect(account.following?(to_be_unfollowed)).to be false - end - - it 'updates the existing follow relationship as expected' do - expect { subject.call(import) }.to change { Follow.where(account: account, target_account: followed).pick(:show_reblogs, :notify, :languages) }.from([true, false, nil]).to([false, true, ['en']]) - end + it 'updates the existing follow relationship as expected and unfollows user not on list, enqueues workers, sends follow reqs after worker run' do + expect { subject.call(import) } + .to change { Follow.where(account: account, target_account: followed).pick(:show_reblogs, :notify, :languages) }.from([true, false, nil]).to([false, true, ['en']]) - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id)) - end - - it 'requests to follow all the expected users once the workers have run' do - subject.call(import) + expect(account) + .to_not be_following(to_be_unfollowed) - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } + expect(row_worker_job_args) + .to match_array(rows[1..].map(&:id)) - Import::RowWorker.drain + stub_resolve_account_and_drain_workers - expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }).to contain_exactly('user@foo.bar', 'unknown@unknown.bar') + expect(FollowRequest.includes(:target_account).where(account: account).map { |follow_request| follow_request.target_account.acct }) + .to contain_exactly('user@foo.bar', 'unknown@unknown.bar') end end @@ -110,30 +88,19 @@ ].map { |data| import.rows.create!(data: data) } end - before do - account.block!(Fabricate(:account, username: 'already_blocked', domain: 'remote.org')) - end - - it 'does not immediately change who the account blocks' do - expect { subject.call(import) }.to_not(change { account.reload.blocking.to_a }) - end + before { account.block!(Fabricate(:account, username: 'already_blocked', domain: 'remote.org')) } - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end - - it 'blocks all the listed users once the workers have run' do - subject.call(import) + it 'does not immediately change who the account blocks, enqueues worker, blocks after run' do + expect { subject.call(import) } + .to_not(change { account.reload.blocking.to_a }) - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } + expect(row_worker_job_args) + .to match_array(rows.map(&:id)) - Import::RowWorker.drain + stub_resolve_account_and_drain_workers - expect(account.blocking.map(&:acct)).to contain_exactly('already_blocked@remote.org', 'user@foo.bar', 'unknown@unknown.bar') + expect(account.reload.blocking.map(&:acct)) + .to contain_exactly('already_blocked@remote.org', 'user@foo.bar', 'unknown@unknown.bar') end end @@ -157,27 +124,18 @@ account.block!(to_be_unblocked) end - it 'unblocks user not present on list' do + it 'unblocks user not present on list, enqueues worker, requests follow after run' do subject.call(import) - expect(account.blocking?(to_be_unblocked)).to be false - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id)) - end - it 'requests to follow all the expected users once the workers have run' do - subject.call(import) + expect(account.blocking?(to_be_unblocked)).to be false - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } + expect(row_worker_job_args) + .to match_array(rows[1..].map(&:id)) - Import::RowWorker.drain + stub_resolve_account_and_drain_workers - expect(account.blocking.map(&:acct)).to contain_exactly('blocked@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') + expect(account.blocking.map(&:acct)) + .to contain_exactly('blocked@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') end end @@ -192,30 +150,19 @@ ].map { |data| import.rows.create!(data: data) } end - before do - account.mute!(Fabricate(:account, username: 'already_muted', domain: 'remote.org')) - end - - it 'does not immediately change who the account blocks' do - expect { subject.call(import) }.to_not(change { account.reload.muting.to_a }) - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end + before { account.mute!(Fabricate(:account, username: 'already_muted', domain: 'remote.org')) } - it 'mutes all the listed users once the workers have run' do - subject.call(import) + it 'does not immediately change who the account blocks, enqueures worker, mutes users after worker run' do + expect { subject.call(import) } + .to_not(change { account.reload.muting.to_a }) - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } + expect(row_worker_job_args) + .to match_array(rows.map(&:id)) - Import::RowWorker.drain + stub_resolve_account_and_drain_workers - expect(account.muting.map(&:acct)).to contain_exactly('already_muted@remote.org', 'user@foo.bar', 'unknown@unknown.bar') + expect(account.reload.muting.map(&:acct)) + .to contain_exactly('already_muted@remote.org', 'user@foo.bar', 'unknown@unknown.bar') end end @@ -239,31 +186,19 @@ account.mute!(to_be_unmuted) end - it 'updates the existing mute as expected' do - expect { subject.call(import) }.to change { Mute.where(account: account, target_account: muted).pick(:hide_notifications) }.from(false).to(true) - end + it 'updates the existing mute as expected and unblocks user not on list, and enqueues worker, and requests follow after worker run' do + expect { subject.call(import) } + .to change { Mute.where(account: account, target_account: muted).pick(:hide_notifications) }.from(false).to(true) - it 'unblocks user not present on list' do - subject.call(import) expect(account.muting?(to_be_unmuted)).to be false - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id)) - end - - it 'requests to follow all the expected users once the workers have run' do - subject.call(import) - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } + expect(row_worker_job_args) + .to match_array(rows[1..].map(&:id)) - Import::RowWorker.drain + stub_resolve_account_and_drain_workers - expect(account.muting.map(&:acct)).to contain_exactly('muted@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') + expect(account.muting.map(&:acct)) + .to contain_exactly('muted@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') end end @@ -284,13 +219,11 @@ account.block_domain!('blocked.com') end - it 'blocks all the new domains' do + it 'blocks all the new domains and marks import finished' do subject.call(import) - expect(account.domain_blocks.pluck(:domain)).to contain_exactly('alreadyblocked.com', 'blocked.com', 'to-block.com') - end - it 'marks the import as finished' do - subject.call(import) + expect(account.domain_blocks.pluck(:domain)) + .to contain_exactly('alreadyblocked.com', 'blocked.com', 'to-block.com') expect(import.reload.state_finished?).to be true end end @@ -312,14 +245,13 @@ account.block_domain!('blocked.com') end - it 'blocks all the new domains' do + it 'blocks all the new domains and marks import finished' do subject.call(import) - expect(account.domain_blocks.pluck(:domain)).to contain_exactly('blocked.com', 'to-block.com') - end - it 'marks the import as finished' do - subject.call(import) - expect(import.reload.state_finished?).to be true + expect(account.domain_blocks.pluck(:domain)) + .to contain_exactly('blocked.com', 'to-block.com') + expect(import.reload.state_finished?) + .to be true end end @@ -347,22 +279,16 @@ account.bookmarks.create!(status: bookmarked) end - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end - - it 'updates the bookmarks as expected once the workers have run' do + it 'enqueues workers for the expected rows and updates bookmarks after worker run' do subject.call(import) - service_double = instance_double(ActivityPub::FetchRemoteStatusService) - allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double) - allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') } - allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) } + expect(row_worker_job_args) + .to match_array(rows.map(&:id)) - Import::RowWorker.drain + stub_fetch_remote_and_drain_workers - expect(account.bookmarks.map { |bookmark| bookmark.status.uri }).to contain_exactly(already_bookmarked.uri, status.uri, bookmarked.uri, 'https://domain.unknown/foo') + expect(account.bookmarks.map { |bookmark| bookmark.status.uri }) + .to contain_exactly(already_bookmarked.uri, status.uri, bookmarked.uri, 'https://domain.unknown/foo') end end @@ -390,23 +316,48 @@ account.bookmarks.create!(status: bookmarked) end - it 'enqueues workers for the expected rows' do + it 'enqueues workers for the expected rows and updates bookmarks' do subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) + + expect(row_worker_job_args) + .to match_array(rows.map(&:id)) + + stub_fetch_remote_and_drain_workers + + expect(account.bookmarks.map { |bookmark| bookmark.status.uri }) + .to contain_exactly(status.uri, bookmarked.uri, 'https://domain.unknown/foo') end + end - it 'updates the bookmarks as expected once the workers have run' do - subject.call(import) + def row_worker_job_args + Import::RowWorker + .jobs + .pluck('args') + .flatten + end - service_double = instance_double(ActivityPub::FetchRemoteStatusService) - allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double) - allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') } - allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) } + def stub_resolve_account_and_drain_workers + resolve_account_service_double = instance_double(ResolveAccountService) + allow(ResolveAccountService) + .to receive(:new) + .and_return(resolve_account_service_double) + allow(resolve_account_service_double) + .to receive(:call) + .with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } + allow(resolve_account_service_double) + .to receive(:call) + .with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } + + Import::RowWorker.drain + end - Import::RowWorker.drain + def stub_fetch_remote_and_drain_workers + service_double = instance_double(ActivityPub::FetchRemoteStatusService) + allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double) + allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') } + allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) } - expect(account.bookmarks.map { |bookmark| bookmark.status.uri }).to contain_exactly(status.uri, bookmarked.uri, 'https://domain.unknown/foo') - end + Import::RowWorker.drain end end end diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb index c39362def2f7f3..123e8699c7668f 100644 --- a/spec/services/favourite_service_spec.rb +++ b/spec/services/favourite_service_spec.rb @@ -11,11 +11,9 @@ let(:bob) { Fabricate(:account) } let(:status) { Fabricate(:status, account: bob) } - before do + it 'creates a favourite' do subject.call(sender, status) - end - it 'creates a favourite' do expect(status.favourites.first).to_not be_nil end end @@ -26,15 +24,16 @@ before do stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {}) - subject.call(sender, status) end - it 'creates a favourite' do - expect(status.favourites.first).to_not be_nil - end + it 'creates a favourite and sends like activity', :inline_jobs do + subject.call(sender, status) + + expect(status.favourites.first) + .to_not be_nil - it 'sends a like activity', :inline_jobs do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once + expect(a_request(:post, 'http://example.com/inbox')) + .to have_been_made.once end end end diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb index 0c4cd600460922..bbd8a6f997ff60 100644 --- a/spec/services/follow_service_spec.rb +++ b/spec/services/follow_service_spec.rb @@ -143,15 +143,16 @@ before do stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {}) - subject.call(sender, bob) end - it 'creates follow request' do - expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil - end + it 'creates follow request and sends an activity to inbox', :inline_jobs do + subject.call(sender, bob) + + expect(FollowRequest.find_by(account: sender, target_account: bob)) + .to_not be_nil - it 'sends a follow activity to the inbox', :inline_jobs do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once + expect(a_request(:post, 'http://example.com/inbox')) + .to have_been_made.once end end end diff --git a/spec/services/process_mentions_service_spec.rb b/spec/services/process_mentions_service_spec.rb index 2c202d3e57af18..3cc83d82f3cb08 100644 --- a/spec/services/process_mentions_service_spec.rb +++ b/spec/services/process_mentions_service_spec.rb @@ -16,20 +16,25 @@ before do account.block!(individually_blocked_account) account.domain_blocks.create!(domain: domain_blocked_account.domain) + end - subject.call(status) + it 'creates a mention to the non-blocked account but not the individually or domain blocked accounts' do + expect { subject.call(status) } + .to create_mention_for_non_blocked + .and skip_mention_for_individual + .and skip_mention_for_domain_blocked end - it 'creates a mention to the non-blocked account' do - expect(non_blocked_account.mentions.where(status: status).count).to eq 1 + def create_mention_for_non_blocked + change { non_blocked_account.mentions.where(status: status).count }.to(1) end - it 'does not create a mention to the individually blocked account' do - expect(individually_blocked_account.mentions.where(status: status).count).to eq 0 + def skip_mention_for_individual + not_change { individually_blocked_account.mentions.where(status: status).count }.from(0) end - it 'does not create a mention to the domain-blocked account' do - expect(domain_blocked_account.mentions.where(status: status).count).to eq 0 + def skip_mention_for_domain_blocked + not_change { domain_blocked_account.mentions.where(status: status).count }.from(0) end end @@ -40,11 +45,9 @@ context 'with a valid remote user' do let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - before do + it 'creates a mention' do subject.call(status) - end - it 'creates a mention' do expect(remote_user.mentions.where(status: status).count).to eq 1 end end @@ -53,11 +56,9 @@ let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct} @#{remote_user.acct} @#{remote_user.acct}", visibility: :public) } - before do + it 'creates exactly one mention' do subject.call(status, save_records: false) - end - it 'creates exactly one mention' do expect(status.mentions.size).to eq 1 end end @@ -66,11 +67,9 @@ let!(:remote_user) { Fabricate(:account, username: 'sneak', protocol: :activitypub, domain: 'xn--hresiar-mxa.ch', inbox_url: 'http://example.com/inbox') } let!(:status) { Fabricate(:status, account: account, text: 'Hello @sneak@hæresiar.ch') } - before do + it 'creates a mention' do subject.call(status) - end - it 'creates a mention' do expect(remote_user.mentions.where(status: status).count).to eq 1 end end @@ -79,11 +78,9 @@ let!(:remote_user) { Fabricate(:account, username: 'foo', protocol: :activitypub, domain: 'xn--y9a3aq.xn--y9a3aq', inbox_url: 'http://example.com/inbox') } let!(:status) { Fabricate(:status, account: account, text: 'Hello @foo@հայ.հայ') } - before do + it 'creates a mention' do subject.call(status) - end - it 'creates a mention' do expect(remote_user.mentions.where(status: status).count).to eq 1 end end @@ -95,10 +92,11 @@ before do stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com').to_return(status: 500) - subject.call(status) end it 'creates a mention' do + subject.call(status) + expect(remote_user.mentions.where(status: status).count).to eq 1 end end diff --git a/spec/services/reject_follow_service_spec.rb b/spec/services/reject_follow_service_spec.rb index d2c7a00206210b..eec0d6c1e05f93 100644 --- a/spec/services/reject_follow_service_spec.rb +++ b/spec/services/reject_follow_service_spec.rb @@ -10,17 +10,15 @@ describe 'local' do let(:bob) { Fabricate(:account) } - before do - FollowRequest.create(account: bob, target_account: sender) - subject.call(bob, sender) - end + before { FollowRequest.create(account: bob, target_account: sender) } - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end + it 'removes follow request and does not create relation' do + subject.call(bob, sender) - it 'does not create follow relation' do - expect(bob.following?(sender)).to be false + expect(bob) + .to_not be_requested(sender) + expect(bob) + .to_not be_following(sender) end end @@ -30,19 +28,17 @@ before do FollowRequest.create(account: bob, target_account: sender) stub_request(:post, bob.inbox_url).to_return(status: 200) - subject.call(bob, sender) - end - - it 'removes follow request' do - expect(bob.requested?(sender)).to be false end - it 'does not create follow relation' do - expect(bob.following?(sender)).to be false - end + it 'removes follow request, does not create relation, sends reject activity', :inline_jobs do + subject.call(bob, sender) - it 'sends a reject activity', :inline_jobs do - expect(a_request(:post, bob.inbox_url)).to have_been_made.once + expect(bob) + .to_not be_requested(sender) + expect(bob) + .to_not be_following(sender) + expect(a_request(:post, bob.inbox_url)) + .to have_been_made.once end end end diff --git a/spec/services/remove_from_followers_service_spec.rb b/spec/services/remove_from_followers_service_spec.rb index 515600096cfc04..381daf1a5913b1 100644 --- a/spec/services/remove_from_followers_service_spec.rb +++ b/spec/services/remove_from_followers_service_spec.rb @@ -10,13 +10,13 @@ describe 'local' do let(:sender) { Fabricate(:account, username: 'alice') } - before do - Follow.create(account: sender, target_account: bob) - subject.call(bob, sender) - end + before { Follow.create(account: sender, target_account: bob) } it 'does not create follow relation' do - expect(bob.followed_by?(sender)).to be false + subject.call(bob, sender) + + expect(bob) + .to_not be_followed_by(sender) end end @@ -26,15 +26,16 @@ before do Follow.create(account: sender, target_account: bob) stub_request(:post, sender.inbox_url).to_return(status: 200) - subject.call(bob, sender) end - it 'does not create follow relation' do - expect(bob.followed_by?(sender)).to be false - end + it 'does not create follow relation and sends reject activity', :inline_jobs do + subject.call(bob, sender) + + expect(bob) + .to_not be_followed_by(sender) - it 'sends a reject activity', :inline_jobs do - expect(a_request(:post, sender.inbox_url)).to have_been_made.once + expect(a_request(:post, sender.inbox_url)) + .to have_been_made.once end end end diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb index 08f519b5360d99..f2b46f05b002ba 100644 --- a/spec/services/remove_status_service_spec.rb +++ b/spec/services/remove_status_service_spec.rb @@ -28,42 +28,38 @@ Fabricate(:status, account: bill, reblog: status, uri: 'hoge') end - it 'removes status from author\'s home feed' do - subject.call(status) - expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status.id) - end - - it 'removes status from local follower\'s home feed' do - subject.call(status) - expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status.id) - end - - it 'publishes to public media timeline' do + it 'removes status from notifications and from author and local follower home feeds, publishes to media timeline, sends delete activities' do allow(redis).to receive(:publish).with(any_args) - subject.call(status) + expect { subject.call(status) } + .to remove_status_from_notifications - expect(redis).to have_received(:publish).with('timeline:public:media', Oj.dump(event: :delete, payload: status.id.to_s)) - end + expect(home_feed_ids(alice)) + .to_not include(status.id) + expect(home_feed_ids(jeff)) + .to_not include(status.id) - it 'sends Delete activity to followers' do - subject.call(status) + expect(redis) + .to have_received(:publish).with('timeline:public:media', Oj.dump(event: :delete, payload: status.id.to_s)) expect(delete_delivery(hank, status)) .to have_been_made.once - end - - it 'sends Delete activity to rebloggers' do - subject.call(status) expect(delete_delivery(bill, status)) .to have_been_made.once end - it 'remove status from notifications' do - expect { subject.call(status) }.to change { - Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count - }.from(1).to(0) + def home_feed_ids(personage) + HomeFeed + .new(personage) + .get(10) + .pluck(:id) + end + + def remove_status_from_notifications + change { Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count } + .from(1) + .to(0) end def delete_delivery(target, status) diff --git a/spec/services/report_service_spec.rb b/spec/services/report_service_spec.rb index 6518c5c27ad3a0..4659e1c7a13ed5 100644 --- a/spec/services/report_service_spec.rb +++ b/spec/services/report_service_spec.rb @@ -31,14 +31,13 @@ context 'when forward is true', :inline_jobs do let(:forward) { true } - it 'sends ActivityPub payload when forward is true' do - subject.call(source_account, remote_account, forward: forward) - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made - end - - it 'has an uri' do + it 'has a URI and sends ActivityPub payload' do report = subject.call(source_account, remote_account, forward: forward) - expect(report.uri).to_not be_nil + + expect(report.uri) + .to_not be_nil + expect(a_request(:post, 'http://example.com/inbox')) + .to have_been_made end context 'when reporting a reply on a different remote server' do @@ -122,13 +121,12 @@ status.mentions.create(account: source_account) end - it 'creates a report' do - expect { subject.call }.to change { target_account.targeted_reports.count }.from(0).to(1) - end + it 'creates a report and attaches the DM to the report' do + expect { subject.call } + .to change { target_account.targeted_reports.count }.from(0).to(1) - it 'attaches the DM to the report' do - subject.call - expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[status.id]] + expect(target_account.targeted_reports.pluck(:status_ids)) + .to eq [[status.id]] end end @@ -146,13 +144,12 @@ status.mentions.create(account: source_account) end - it 'creates a report' do - expect { subject.call }.to change { target_account.targeted_reports.count }.from(0).to(1) - end + it 'creates a report and attaches DM to report' do + expect { subject.call } + .to change { target_account.targeted_reports.count }.from(0).to(1) - it 'attaches the DM to the report' do - subject.call - expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[status.id]] + expect(target_account.targeted_reports.pluck(:status_ids)) + .to eq [[status.id]] end end diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb index a856e019a7fe2f..1bd4e9a8e3bfcc 100644 --- a/spec/services/resolve_account_service_spec.rb +++ b/spec/services/resolve_account_service_spec.rb @@ -22,37 +22,38 @@ context 'when domain is banned' do before { Fabricate(:domain_block, domain: 'ap.example.com', severity: :suspend) } - it 'does not return an account' do - expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to be_nil - end - - it 'does not make a webfinger query' do - subject.call('foo@ap.example.com', skip_webfinger: true) - expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made + it 'does not return an account or make a webfinger query' do + expect(subject.call('foo@ap.example.com', skip_webfinger: true)) + .to be_nil + expect(webfinger_discovery_request) + .to_not have_been_made end end context 'when domain is not banned' do - it 'returns the expected account' do - expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to eq remote_account - end - - it 'does not make a webfinger query' do - subject.call('foo@ap.example.com', skip_webfinger: true) - expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made + it 'returns the expected account and does not make a webfinger query' do + expect(subject.call('foo@ap.example.com', skip_webfinger: true)) + .to eq remote_account + expect(webfinger_discovery_request) + .to_not have_been_made end end end context 'when account is not known' do - it 'does not return an account' do - expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to be_nil + it 'does not return an account and does not make webfinger query' do + expect(subject.call('foo@ap.example.com', skip_webfinger: true)) + .to be_nil + expect(webfinger_discovery_request) + .to_not have_been_made end + end - it 'does not make a webfinger query' do - subject.call('foo@ap.example.com', skip_webfinger: true) - expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made - end + def webfinger_discovery_request + a_request( + :get, + 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com' + ) end end @@ -84,13 +85,11 @@ allow(AccountDeletionWorker).to receive(:perform_async) end - it 'returns nil' do - expect(subject.call('hoge@example.com')).to be_nil - end - - it 'queues account deletion worker' do - subject.call('hoge@example.com') - expect(AccountDeletionWorker).to have_received(:perform_async) + it 'returns nil and queues deletion worker' do + expect(subject.call('hoge@example.com')) + .to be_nil + expect(AccountDeletionWorker) + .to have_received(:perform_async) end end @@ -110,9 +109,12 @@ it 'returns new remote account' do account = subject.call('Foo@redirected.example.com') - expect(account.activitypub?).to be true - expect(account.acct).to eq 'foo@ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' + expect(account) + .to have_attributes( + activitypub?: true, + acct: 'foo@ap.example.com', + inbox_url: 'https://ap.example.com/users/foo/inbox' + ) end end @@ -125,9 +127,12 @@ it 'returns new remote account' do account = subject.call('Foo@redirected.example.com') - expect(account.activitypub?).to be true - expect(account.acct).to eq 'foo@ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' + expect(account) + .to have_attributes( + activitypub?: true, + acct: 'foo@ap.example.com', + inbox_url: 'https://ap.example.com/users/foo/inbox' + ) end end @@ -161,9 +166,12 @@ it 'returns new remote account' do account = subject.call('foo@ap.example.com') - expect(account.activitypub?).to be true - expect(account.domain).to eq 'ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' + expect(account) + .to have_attributes( + activitypub?: true, + domain: 'ap.example.com', + inbox_url: 'https://ap.example.com/users/foo/inbox' + ) end context 'with multiple types' do @@ -174,10 +182,13 @@ it 'returns new remote account' do account = subject.call('foo@ap.example.com') - expect(account.activitypub?).to be true - expect(account.domain).to eq 'ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - expect(account.actor_type).to eq 'Person' + expect(account) + .to have_attributes( + activitypub?: true, + domain: 'ap.example.com', + inbox_url: 'https://ap.example.com/users/foo/inbox', + actor_type: 'Person' + ) end end end @@ -186,20 +197,21 @@ let!(:duplicate) { Fabricate(:account, username: 'foo', domain: 'old.example.com', uri: 'https://ap.example.com/users/foo') } let!(:status) { Fabricate(:status, account: duplicate, text: 'foo') } - it 'returns new remote account' do + it 'returns new remote account and merges accounts', :inline_jobs do account = subject.call('foo@ap.example.com') - expect(account.activitypub?).to be true - expect(account.domain).to eq 'ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - expect(account.uri).to eq 'https://ap.example.com/users/foo' - end - - it 'merges accounts', :inline_jobs do - account = subject.call('foo@ap.example.com') + expect(account) + .to have_attributes( + activitypub?: true, + domain: 'ap.example.com', + inbox_url: 'https://ap.example.com/users/foo/inbox', + uri: 'https://ap.example.com/users/foo' + ) - expect(status.reload.account_id).to eq account.id - expect(Account.where(uri: account.uri).count).to eq 1 + expect(status.reload.account_id) + .to eq account.id + expect(Account.where(uri: account.uri).count) + .to eq 1 end end @@ -210,11 +222,15 @@ it 'returns new remote account' do account = subject.call('foo@ap.example.com') - expect(account.activitypub?).to be true - expect(account.domain).to eq 'ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - expect(account.uri).to eq 'https://ap.example.com/users/foo' - expect(status.reload.account).to eq(account) + expect(account) + .to have_attributes( + activitypub?: true, + domain: 'ap.example.com', + inbox_url: 'https://ap.example.com/users/foo/inbox', + uri: 'https://ap.example.com/users/foo' + ) + expect(status.reload.account) + .to eq(account) end end diff --git a/spec/services/resolve_url_service_spec.rb b/spec/services/resolve_url_service_spec.rb index 80f2a5a4baf55d..eaf00c1ed84cd2 100644 --- a/spec/services/resolve_url_service_spec.rb +++ b/spec/services/resolve_url_service_spec.rb @@ -51,12 +51,11 @@ let(:url) { 'https://example.com/@foo/42' } let(:uri) { 'https://example.com/users/foo/statuses/42' } - it 'returns status by url' do - expect(subject.call(url, on_behalf_of: account)).to eq(status) - end - - it 'returns status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to eq(status) + it 'returns status by URL or URI' do + expect(subject.call(url, on_behalf_of: account)) + .to eq(status) + expect(subject.call(uri, on_behalf_of: account)) + .to eq(status) end end @@ -75,12 +74,11 @@ let(:url) { 'https://example.com/@foo/42' } let(:uri) { 'https://example.com/users/foo/statuses/42' } - it 'does not return the status by url' do - expect(subject.call(url, on_behalf_of: account)).to be_nil - end - - it 'does not return the status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to be_nil + it 'does not return the status by URL or URI' do + expect(subject.call(url, on_behalf_of: account)) + .to be_nil + expect(subject.call(uri, on_behalf_of: account)) + .to be_nil end end @@ -107,22 +105,20 @@ account.follow!(poster) end - it 'returns status by url' do - expect(subject.call(url, on_behalf_of: account)).to eq(status) - end - - it 'returns status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to eq(status) + it 'returns status by URL or URI' do + expect(subject.call(url, on_behalf_of: account)) + .to eq(status) + expect(subject.call(uri, on_behalf_of: account)) + .to eq(status) end end context 'when the account does not follow the poster' do - it 'does not return the status by url' do - expect(subject.call(url, on_behalf_of: account)).to be_nil - end - - it 'does not return the status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to be_nil + it 'does not return the status by URL or URI' do + expect(subject.call(url, on_behalf_of: account)) + .to be_nil + expect(subject.call(uri, on_behalf_of: account)) + .to be_nil end end end diff --git a/spec/services/translate_status_service_spec.rb b/spec/services/translate_status_service_spec.rb index 0779fbbe6c52bc..cd92fb8d1025ab 100644 --- a/spec/services/translate_status_service_spec.rb +++ b/spec/services/translate_status_service_spec.rb @@ -32,20 +32,14 @@ allow(TranslationService).to receive_messages(configured?: true, configured: translation_service) end - it 'returns translated status content' do - expect(service.call(status, 'es').content).to eq '

Hola

' - end - - it 'returns source language' do - expect(service.call(status, 'es').detected_source_language).to eq 'en' - end - - it 'returns translation provider' do - expect(service.call(status, 'es').provider).to eq 'Dummy' - end - - it 'returns original status' do - expect(service.call(status, 'es').status).to eq status + it 'returns translated status content and source language and provider and original status' do + expect(service.call(status, 'es')) + .to have_attributes( + content: '

Hola

', + detected_source_language: 'en', + provider: 'Dummy', + status: status + ) end describe 'status has content with custom emoji' do @@ -155,26 +149,16 @@ let!(:source_texts) { service.send(:source_texts) } it 'returns formatted poll options' do - expect(source_texts.size).to eq 3 - expect(source_texts.values).to eq %w(

Hello

Blue Green) - end - - it 'has a first key with content' do - expect(source_texts.keys.first).to eq :content - end - - it 'has the first option in the second key with correct options' do - option1 = source_texts.keys.second - expect(option1).to be_a Poll::Option - expect(option1.id).to eq '0' - expect(option1.title).to eq 'Blue' - end - - it 'has the second option in the third key with correct options' do - option2 = source_texts.keys.third - expect(option2).to be_a Poll::Option - expect(option2.id).to eq '1' - expect(option2.title).to eq 'Green' + expect(source_texts) + .to have_attributes( + size: 3, + values: %w(

Hello

Blue Green), + keys: contain_exactly( + eq(:content), + be_a(Poll::Option).and(have_attributes(id: '0', title: 'Blue')), + be_a(Poll::Option).and(have_attributes(id: '1', title: 'Green')) + ) + ) end end end diff --git a/spec/services/unblock_domain_service_spec.rb b/spec/services/unblock_domain_service_spec.rb index 405fe1cfd2f8a3..daa1d480a6bc9d 100644 --- a/spec/services/unblock_domain_service_spec.rb +++ b/spec/services/unblock_domain_service_spec.rb @@ -12,26 +12,32 @@ let!(:silenced) { Fabricate(:account, domain: 'example.com', silenced_at: domain_block.created_at) } let!(:suspended) { Fabricate(:account, domain: 'example.com', suspended_at: domain_block.created_at) } - it 'unsilences accounts and removes block' do - domain_block.update(severity: :silence) - - subject.call(domain_block) - expect_deleted_domain_block - expect(silenced.reload.silenced?).to be false - expect(suspended.reload.suspended?).to be true - expect(independently_suspended.reload.suspended?).to be true - expect(independently_silenced.reload.silenced?).to be true + context 'with severity of silence' do + before { domain_block.update(severity: :silence) } + + it 'unsilences accounts and removes block' do + subject.call(domain_block) + + expect_deleted_domain_block + expect(silenced.reload.silenced?).to be false + expect(suspended.reload.suspended?).to be true + expect(independently_suspended.reload.suspended?).to be true + expect(independently_silenced.reload.silenced?).to be true + end end - it 'unsuspends accounts and removes block' do - domain_block.update(severity: :suspend) + context 'with severity of suspend' do + before { domain_block.update(severity: :suspend) } - subject.call(domain_block) - expect_deleted_domain_block - expect(suspended.reload.suspended?).to be false - expect(silenced.reload.silenced?).to be false - expect(independently_suspended.reload.suspended?).to be true - expect(independently_silenced.reload.silenced?).to be true + it 'unsuspends accounts and removes block' do + subject.call(domain_block) + + expect_deleted_domain_block + expect(suspended.reload.suspended?).to be false + expect(silenced.reload.silenced?).to be false + expect(independently_suspended.reload.suspended?).to be true + expect(independently_silenced.reload.silenced?).to be true + end end end diff --git a/spec/services/unblock_service_spec.rb b/spec/services/unblock_service_spec.rb index 6132e74415ecd6..a2c5188f06335a 100644 --- a/spec/services/unblock_service_spec.rb +++ b/spec/services/unblock_service_spec.rb @@ -10,13 +10,13 @@ describe 'local' do let(:bob) { Fabricate(:account) } - before do - sender.block!(bob) - subject.call(sender, bob) - end + before { sender.block!(bob) } it 'destroys the blocking relation' do - expect(sender.blocking?(bob)).to be false + subject.call(sender, bob) + + expect(sender) + .to_not be_blocking(bob) end end @@ -26,15 +26,15 @@ before do sender.block!(bob) stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - subject.call(sender, bob) end - it 'destroys the blocking relation' do - expect(sender.blocking?(bob)).to be false - end + it 'destroys the blocking relation and sends unblock activity', :inline_jobs do + subject.call(sender, bob) - it 'sends an unblock activity', :inline_jobs do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once + expect(sender) + .to_not be_blocking(bob) + expect(a_request(:post, 'http://example.com/inbox')) + .to have_been_made.once end end end diff --git a/spec/services/unfollow_service_spec.rb b/spec/services/unfollow_service_spec.rb index 0c206c4b983215..6cf24ca5e1ce65 100644 --- a/spec/services/unfollow_service_spec.rb +++ b/spec/services/unfollow_service_spec.rb @@ -10,13 +10,13 @@ describe 'local' do let(:bob) { Fabricate(:account, username: 'bob') } - before do - sender.follow!(bob) - subject.call(sender, bob) - end + before { sender.follow!(bob) } it 'destroys the following relation' do - expect(sender.following?(bob)).to be false + subject.call(sender, bob) + + expect(sender) + .to_not be_following(bob) end end @@ -26,15 +26,15 @@ before do sender.follow!(bob) stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - subject.call(sender, bob) end - it 'destroys the following relation' do - expect(sender.following?(bob)).to be false - end + it 'destroys the following relation and sends unfollow activity' do + subject.call(sender, bob) - it 'sends an unfollow activity' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once + expect(sender) + .to_not be_following(bob) + expect(a_request(:post, 'http://example.com/inbox')) + .to have_been_made.once end end @@ -44,15 +44,15 @@ before do bob.follow!(sender) stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - subject.call(bob, sender) end - it 'destroys the following relation' do - expect(bob.following?(sender)).to be false - end + it 'destroys the following relation and sends a reject activity' do + subject.call(bob, sender) - it 'sends a reject activity' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once + expect(sender) + .to_not be_following(bob) + expect(a_request(:post, 'http://example.com/inbox')) + .to have_been_made.once end end end diff --git a/spec/services/update_account_service_spec.rb b/spec/services/update_account_service_spec.rb index d066db481e5568..f9059af07f5ab3 100644 --- a/spec/services/update_account_service_spec.rb +++ b/spec/services/update_account_service_spec.rb @@ -18,23 +18,19 @@ FollowService.new.call(alice, account) FollowService.new.call(bob, account) FollowService.new.call(eve, account) + end + it 'auto accepts pending follow requests from appropriate accounts' do subject.call(account, { locked: false }) - end - it 'auto-accepts pending follow requests' do - expect(alice.following?(account)).to be true - expect(alice.requested?(account)).to be false - end + expect(alice).to be_following(account) + expect(alice).to_not be_requested(account) - it 'does not auto-accept pending follow requests from silenced users' do - expect(bob.following?(account)).to be false - expect(bob.requested?(account)).to be true - end + expect(bob).to_not be_following(account) + expect(bob).to be_requested(account) - it 'auto-accepts pending follow requests from muted users so as to not leak mute' do - expect(eve.following?(account)).to be true - expect(eve.requested?(account)).to be false + expect(eve).to be_following(account) + expect(eve).to_not be_requested(account) end end end diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb index de06fb13c63ad5..7c92adeffd2335 100644 --- a/spec/services/update_status_service_spec.rb +++ b/spec/services/update_status_service_spec.rb @@ -10,15 +10,15 @@ before do allow(ActivityPub::DistributionWorker).to receive(:perform_async) - subject.call(status, status.account_id, text: 'Foo') end - it 'does not create an edit' do - expect(status.reload.edits).to be_empty - end + it 'does not create an edit or notify anyone' do + subject.call(status, status.account_id, text: 'Foo') - it 'does not notify anyone' do - expect(ActivityPub::DistributionWorker).to_not have_received(:perform_async) + expect(status.reload.edits) + .to be_empty + expect(ActivityPub::DistributionWorker) + .to_not have_received(:perform_async) end end @@ -28,18 +28,16 @@ before do PreviewCardsStatus.create(status: status, preview_card: preview_card) - subject.call(status, status.account_id, text: 'Bar') - end - - it 'updates text' do - expect(status.reload.text).to eq 'Bar' end - it 'resets preview card' do - expect(status.reload.preview_card).to be_nil - end + it 'updates text, resets card, saves edit history' do + subject.call(status, status.account_id, text: 'Bar') - it 'saves edit history' do + expect(status.reload) + .to have_attributes( + text: 'Bar', + preview_card: be_nil + ) expect(status.edits.ordered.pluck(:text)).to eq %w(Foo Bar) end end @@ -50,15 +48,15 @@ before do PreviewCardsStatus.create(status: status, preview_card: preview_card) - subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar') end - it 'updates content warning' do - expect(status.reload.spoiler_text).to eq 'Bar' - end + it 'updates content warning and saves history' do + subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar') - it 'saves edit history' do - expect(status.edits.ordered.pluck(:text, :spoiler_text)).to eq [['Foo', ''], ['Foo', 'Bar']] + expect(status.reload.spoiler_text) + .to eq 'Bar' + expect(status.edits.ordered.pluck(:text, :spoiler_text)) + .to eq [['Foo', ''], ['Foo', 'Bar']] end end @@ -69,23 +67,19 @@ before do status.media_attachments << detached_media_attachment - subject.call(status, status.account_id, text: 'Foo', media_ids: [attached_media_attachment.id.to_s]) - end - - it 'updates media attachments' do - expect(status.ordered_media_attachments).to eq [attached_media_attachment] - end - - it 'does not detach detached media attachments' do - expect(detached_media_attachment.reload.status_id).to eq status.id end - it 'attaches attached media attachments' do - expect(attached_media_attachment.reload.status_id).to eq status.id - end + it 'updates media attachments, handles attachments, saves history' do + subject.call(status, status.account_id, text: 'Foo', media_ids: [attached_media_attachment.id.to_s]) - it 'saves edit history' do - expect(status.edits.ordered.pluck(:ordered_media_attachment_ids)).to eq [[detached_media_attachment.id], [attached_media_attachment.id]] + expect(status.ordered_media_attachments) + .to eq [attached_media_attachment] + expect(detached_media_attachment.reload.status_id) + .to eq status.id + expect(attached_media_attachment.reload.status_id) + .to eq status.id + expect(status.edits.ordered.pluck(:ordered_media_attachment_ids)) + .to eq [[detached_media_attachment.id], [attached_media_attachment.id]] end end @@ -95,19 +89,18 @@ before do status.media_attachments << media_attachment - subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id.to_s], media_attributes: [{ id: media_attachment.id, description: 'New description' }]) end - it 'does not detach media attachment' do - expect(media_attachment.reload.status_id).to eq status.id - end - - it 'updates the media attachment description' do - expect(media_attachment.reload.description).to eq 'New description' - end + it 'does not detach media attachment, updates description, and saves history' do + subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id.to_s], media_attributes: [{ id: media_attachment.id, description: 'New description' }]) - it 'saves edit history' do - expect(status.edits.ordered.map { |edit| edit.ordered_media_attachments.map(&:description) }).to eq [['Old description'], ['New description']] + expect(media_attachment.reload) + .to have_attributes( + status_id: status.id, + description: 'New description' + ) + expect(status.edits.ordered.map { |edit| edit.ordered_media_attachments.map(&:description) }) + .to eq [['Old description'], ['New description']] end end @@ -120,28 +113,27 @@ before do status.update(poll: poll) VoteService.new.call(voter, poll, [0]) - subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i }) end - it 'updates poll' do - poll = status.poll.reload - expect(poll.options).to eq %w(Bar Baz Foo) - end + it 'updates poll, resets votes, saves history, requeues notifications' do + subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i }) - it 'resets votes' do poll = status.poll.reload - expect(poll.votes_count).to eq 0 - expect(poll.votes.count).to eq 0 - expect(poll.cached_tallies).to eq [0, 0, 0] - end - it 'saves edit history' do - expect(status.edits.ordered.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)] - end + expect(poll) + .to have_attributes( + options: %w(Bar Baz Foo), + votes_count: 0, + cached_tallies: [0, 0, 0] + ) + expect(poll.votes.count) + .to eq(0) - it 'requeues expiration notification' do - poll = status.poll.reload - expect(PollExpirationNotifyWorker).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes) + expect(status.edits.ordered.pluck(:poll_options)) + .to eq [%w(Foo Bar), %w(Bar Baz Foo)] + + expect(PollExpirationNotifyWorker) + .to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes) end end @@ -151,16 +143,13 @@ let!(:bob) { Fabricate(:account, username: 'bob') } let!(:status) { PostStatusService.new.call(account, text: 'Hello @alice') } - before do + it 'changes mentions and keeps old as silent' do subject.call(status, status.account_id, text: 'Hello @bob') - end - - it 'changes mentions' do - expect(status.active_mentions.pluck(:account_id)).to eq [bob.id] - end - it 'keeps old mentions as silent mentions' do - expect(status.mentions.pluck(:account_id)).to contain_exactly(alice.id, bob.id) + expect(status.active_mentions.pluck(:account_id)) + .to eq [bob.id] + expect(status.mentions.pluck(:account_id)) + .to contain_exactly(alice.id, bob.id) end end @@ -168,11 +157,9 @@ let!(:account) { Fabricate(:account) } let!(:status) { PostStatusService.new.call(account, text: 'Hello #foo') } - before do + it 'changes tags' do subject.call(status, status.account_id, text: 'Hello #bar') - end - it 'changes tags' do expect(status.tags.pluck(:name)).to eq %w(bar) end end diff --git a/spec/support/response_encoders.rb b/spec/support/response_encoders.rb new file mode 100644 index 00000000000000..548dba7132486f --- /dev/null +++ b/spec/support/response_encoders.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +ActionDispatch::IntegrationTest + .register_encoder :xml, response_parser: ->(body) { Nokogiri::XML(body) } diff --git a/spec/system/invites_spec.rb b/spec/system/invites_spec.rb index c57de871cc6e1a..fc60ce5913bc03 100644 --- a/spec/system/invites_spec.rb +++ b/spec/system/invites_spec.rb @@ -7,10 +7,7 @@ let(:user) { Fabricate :user } - before do - host! 'localhost:3000' # TODO: Move into before for all system specs? - sign_in user - end + before { sign_in user } describe 'Viewing invites' do it 'Lists existing user invites' do diff --git a/spec/system/oauth_spec.rb b/spec/system/oauth_spec.rb index 0f96a59675803b..64ac75879e666d 100644 --- a/spec/system/oauth_spec.rb +++ b/spec/system/oauth_spec.rb @@ -179,7 +179,7 @@ end context 'when the user has set up TOTP' do - let(:user) { Fabricate(:user, email: email, password: password, otp_required_for_login: true, otp_secret: User.generate_otp_secret(32)) } + let(:user) { Fabricate(:user, email: email, password: password, otp_required_for_login: true, otp_secret: User.generate_otp_secret) } it 'when accepting the authorization request' do params = { client_id: client_app.uid, response_type: 'code', redirect_uri: client_app.redirect_uri, scope: 'read' } diff --git a/spec/system/report_interface_spec.rb b/spec/system/report_interface_spec.rb index 257a1cd6fd371c..6a90aa5bc66655 100644 --- a/spec/system/report_interface_spec.rb +++ b/spec/system/report_interface_spec.rb @@ -28,4 +28,17 @@ page.scroll_to(page.find('.batch-table__row')) expect(page).to have_css('.spoiler-button__overlay__label') end + + it 'marks a report resolved from the show page actions area' do + visit admin_report_path(report) + + expect { resolve_report } + .to change { report.reload.action_taken_at }.to(be_present).from(nil) + end + + def resolve_report + within '.report-actions' do + click_on I18n.t('admin.reports.mark_as_resolved') + end + end end diff --git a/spec/workers/mention_resolve_worker_spec.rb b/spec/workers/mention_resolve_worker_spec.rb new file mode 100644 index 00000000000000..5e23876b4ae4f8 --- /dev/null +++ b/spec/workers/mention_resolve_worker_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe MentionResolveWorker do + let(:status_id) { -42 } + let(:uri) { 'https://example.com/users/unknown' } + + describe '#perform' do + subject { described_class.new.perform(status_id, uri, {}) } + + context 'with a non-existent status' do + it 'returns nil' do + expect(subject).to be_nil + end + end + + context 'with a valid user' do + let(:status) { Fabricate(:status) } + let(:status_id) { status.id } + + let(:service_double) { instance_double(ActivityPub::FetchRemoteAccountService) } + + before do + allow(ActivityPub::FetchRemoteAccountService).to receive(:new).and_return(service_double) + + allow(service_double).to receive(:call).with(uri, anything) { Fabricate(:account, domain: 'example.com', uri: uri) } + end + + it 'resolves the account and adds a new mention', :aggregate_failures do + expect { subject } + .to change { status.reload.mentions }.from([]).to(a_collection_including(having_attributes(account: having_attributes(uri: uri), silent: false))) + + expect(service_double).to have_received(:call).once + end + end + end +end diff --git a/spec/workers/web/push_notification_worker_spec.rb b/spec/workers/web/push_notification_worker_spec.rb index ced21d5bf799b4..7f836d99e431f9 100644 --- a/spec/workers/web/push_notification_worker_spec.rb +++ b/spec/workers/web/push_notification_worker_spec.rb @@ -22,27 +22,48 @@ let(:payload) { { ciphertext: ciphertext, salt: salt, server_public_key: server_public_key, shared_secret: shared_secret } } describe 'perform' do + around do |example| + original_private = Rails.configuration.x.vapid_private_key + original_public = Rails.configuration.x.vapid_public_key + Rails.configuration.x.vapid_private_key = vapid_private_key + Rails.configuration.x.vapid_public_key = vapid_public_key + example.run + Rails.configuration.x.vapid_private_key = original_private + Rails.configuration.x.vapid_public_key = original_public + end + before do - allow(subscription).to receive_messages(contact_email: contact_email, vapid_key: vapid_key) - allow(Web::PushSubscription).to receive(:find).with(subscription.id).and_return(subscription) + Setting.site_contact_email = contact_email + allow(Webpush::Encryption).to receive(:encrypt).and_return(payload) allow(JWT).to receive(:encode).and_return('jwt.encoded.payload') stub_request(:post, endpoint).to_return(status: 201, body: '') + end + it 'calls the relevant service with the correct headers' do subject.perform(subscription.id, notification.id) + + expect(web_push_endpoint_request) + .to have_been_made end - it 'calls the relevant service with the correct headers' do - expect(a_request(:post, endpoint).with(headers: { - 'Content-Encoding' => 'aesgcm', - 'Content-Type' => 'application/octet-stream', - 'Crypto-Key' => "dh=BAgtUks5d90kFmxGevk9tH7GEmvz9DB0qcEMUsOBgKwMf-TMjsKIIG6LQvGcFAf6jcmAod15VVwmYwGIIxE4VWE;p256ecdsa=#{vapid_public_key.delete('=')}", - 'Encryption' => 'salt=WJeVM-RY-F9351SVxTFx_g', - 'Ttl' => '172800', - 'Urgency' => 'normal', - 'Authorization' => 'WebPush jwt.encoded.payload', - }, body: "+\xB8\xDBT}\u0013\xB6\xDD.\xF9\xB0\xA7\xC8Ҁ\xFD\x99#\xF7\xAC\x83\xA4\xDB,\u001F\xB5\xB9w\x85>\xF7\xADr")).to have_been_made + def web_push_endpoint_request + a_request( + :post, + endpoint + ).with( + headers: { + 'Content-Encoding' => 'aesgcm', + 'Content-Type' => 'application/octet-stream', + 'Crypto-Key' => "dh=BAgtUks5d90kFmxGevk9tH7GEmvz9DB0qcEMUsOBgKwMf-TMjsKIIG6LQvGcFAf6jcmAod15VVwmYwGIIxE4VWE;p256ecdsa=#{vapid_public_key.delete('=')}", + 'Encryption' => 'salt=WJeVM-RY-F9351SVxTFx_g', + 'Ttl' => '172800', + 'Urgency' => 'normal', + 'Authorization' => 'WebPush jwt.encoded.payload', + }, + body: "+\xB8\xDBT}\u0013\xB6\xDD.\xF9\xB0\xA7\xC8Ҁ\xFD\x99#\xF7\xAC\x83\xA4\xDB,\u001F\xB5\xB9w\x85>\xF7\xADr" + ) end end end diff --git a/streaming/Dockerfile b/streaming/Dockerfile index 938f1655d15d24..bed6b637380dac 100644 --- a/streaming/Dockerfile +++ b/streaming/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.9 +# syntax=docker/dockerfile:1.10 # Please see https://docs.docker.com/engine/reference/builder for information about # the extended buildx capabilities used in this file. diff --git a/yarn.lock b/yarn.lock index 628b3c43ad9221..39f21d3014a0ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,127 +42,127 @@ __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.7": - version: 7.24.7 - resolution: "@babel/code-frame@npm:7.24.7" +"@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.25.7": + version: 7.25.7 + resolution: "@babel/code-frame@npm:7.25.7" dependencies: - "@babel/highlight": "npm:^7.24.7" + "@babel/highlight": "npm:^7.25.7" picocolors: "npm:^1.0.0" - checksum: 10c0/ab0af539473a9f5aeaac7047e377cb4f4edd255a81d84a76058595f8540784cc3fbe8acf73f1e073981104562490aabfb23008cd66dc677a456a4ed5390fdde6 + checksum: 10c0/14825c298bdec914caf3d24d1383b6d4cd6b030714686004992f4fc251831ecf432236652896f99d5d341f17170ae9a07b58d8d7b15aa0df8cfa1c5a7d5474bc languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.2, @babel/compat-data@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/compat-data@npm:7.25.4" - checksum: 10c0/50d79734d584a28c69d6f5b99adfaa064d0f41609a378aef04eb06accc5b44f8520e68549eba3a082478180957b7d5783f1bfb1672e4ae8574e797ce8bae79fa +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/compat-data@npm:7.25.7" + checksum: 10c0/e5cc915abdd18d021236474a96606b2d4a915c4fb620c1ad776b8a08d91111e788cb3b7e9bad43593d4e0bfa4f06894357bcb0984102de1861b9e7322b6bc9f8 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.25.2 - resolution: "@babel/core@npm:7.25.2" + version: 7.25.7 + resolution: "@babel/core@npm:7.25.7" dependencies: "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.25.0" - "@babel/helper-compilation-targets": "npm:^7.25.2" - "@babel/helper-module-transforms": "npm:^7.25.2" - "@babel/helpers": "npm:^7.25.0" - "@babel/parser": "npm:^7.25.0" - "@babel/template": "npm:^7.25.0" - "@babel/traverse": "npm:^7.25.2" - "@babel/types": "npm:^7.25.2" + "@babel/code-frame": "npm:^7.25.7" + "@babel/generator": "npm:^7.25.7" + "@babel/helper-compilation-targets": "npm:^7.25.7" + "@babel/helper-module-transforms": "npm:^7.25.7" + "@babel/helpers": "npm:^7.25.7" + "@babel/parser": "npm:^7.25.7" + "@babel/template": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" + "@babel/types": "npm:^7.25.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/a425fa40e73cb72b6464063a57c478bc2de9dbcc19c280f1b55a3d88b35d572e87e8594e7d7b4880331addb6faef641bbeb701b91b41b8806cd4deae5d74f401 + checksum: 10c0/dad20af39624086afc3a0910bd97ae712c9ad0e9dda09fc5da93876e8ea1802b63ddd81c44f4aa8a9834db46de801eaab1ce9b81ab54b4fe907ae052c24de136 languageName: node linkType: hard -"@babel/generator@npm:^7.25.0, @babel/generator@npm:^7.25.4, @babel/generator@npm:^7.7.2": - version: 7.25.4 - resolution: "@babel/generator@npm:7.25.4" +"@babel/generator@npm:^7.25.7, @babel/generator@npm:^7.7.2": + version: 7.25.7 + resolution: "@babel/generator@npm:7.25.7" dependencies: - "@babel/types": "npm:^7.25.4" + "@babel/types": "npm:^7.25.7" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" - jsesc: "npm:^2.5.1" - checksum: 10c0/a2d8cc39e759214740f836360c8d9c17aa93e16e41afe73368a9e7ccd1d5c3303a420ce3aca1c9a31fdb93d1899de471d5aac97d1c64f741f8750a25a6e91fbc + jsesc: "npm:^3.0.2" + checksum: 10c0/c03a26c79864d60d04ce36b649c3fa0d6fd7b2bf6a22e22854a0457aa09206508392dd73ee40e7bc8d50b3602f9ff068afa47770cda091d332e7db1ca382ee96 languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-annotate-as-pure@npm:7.24.7" +"@babel/helper-annotate-as-pure@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.25.7" dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10c0/4679f7df4dffd5b3e26083ae65228116c3da34c3fff2c11ae11b259a61baec440f51e30fd236f7a0435b9d471acd93d0bc5a95df8213cbf02b1e083503d81b9a + "@babel/types": "npm:^7.25.7" + checksum: 10c0/2f020b0fa9d336b5778485cc2de3141561ec436a7591b685457a5bcdae4ce41d9ddee68169c95504e0789e5a4327e73b8b7e72e5b60e82e96d730c4d19255248 languageName: node linkType: hard -"@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" +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.25.7" dependencies: - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/0ed84abf848c79fb1cd4c1ddac12c771d32c1904d87fc3087f33cfdeb0c2e0db4e7892b74b407d9d8d0c000044f3645a7391a781f788da8410c290bb123a1f13 + "@babel/traverse": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/e9dc5a7920a1d74150dec53ccd5e34f2b31ae307df7cdeec6289866f7bda97ecb1328b49a7710ecde5db5b6daad768c904a030f9a0fa3184963b0017622c42aa languageName: node linkType: hard -"@babel/helper-builder-react-jsx@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-builder-react-jsx@npm:7.24.7" +"@babel/helper-builder-react-jsx@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-builder-react-jsx@npm:7.25.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/c95c8856c67c57060461f39b669707b2dca3501149bcc54b7c3e49c95069afce52179fc7c2bd809981acfbfdf0860ef1035dd7512cdba46c83bdb1ad6f6dc53f + "@babel/helper-annotate-as-pure": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/f8123a76e8c3fcdbb24cc14bfefc80e4c7bf58112ab26bea3247298748c674cbaee70591c362d0d881e4d88154ea4809b145f3ddcf96221cf55ba27bfde535c6 languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.7, @babel/helper-compilation-targets@npm:^7.24.8, @babel/helper-compilation-targets@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/helper-compilation-targets@npm:7.25.2" +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-compilation-targets@npm:7.25.7" dependencies: - "@babel/compat-data": "npm:^7.25.2" - "@babel/helper-validator-option": "npm:^7.24.8" - browserslist: "npm:^4.23.1" + "@babel/compat-data": "npm:^7.25.7" + "@babel/helper-validator-option": "npm:^7.25.7" + browserslist: "npm:^4.24.0" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10c0/de10e986b5322c9f807350467dc845ec59df9e596a5926a3b5edbb4710d8e3b8009d4396690e70b88c3844fe8ec4042d61436dd4b92d1f5f75655cf43ab07e99 + checksum: 10c0/705be7e5274a3fdade68e3e2cf42e2b600316ab52794e13b91299a16f16c926f15886b6e9d6df20eb943ccc1cdba5a363d4766f8d01e47b8e6f4e01175f5e66c languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.24.7, @babel/helper-create-class-features-plugin@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/helper-create-class-features-plugin@npm:7.25.4" +"@babel/helper-create-class-features-plugin@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-member-expression-to-functions": "npm:^7.24.8" - "@babel/helper-optimise-call-expression": "npm:^7.24.7" - "@babel/helper-replace-supers": "npm:^7.25.0" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" - "@babel/traverse": "npm:^7.25.4" + "@babel/helper-annotate-as-pure": "npm:^7.25.7" + "@babel/helper-member-expression-to-functions": "npm:^7.25.7" + "@babel/helper-optimise-call-expression": "npm:^7.25.7" + "@babel/helper-replace-supers": "npm:^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/a765d9e0482e13cf96642fa8aa28e6f7d4d7d39f37840d6246e5e10a7c47f47c52d52522edd3073f229449d17ec0db6f9b7b5e398bff6bb0b4994d65957a164c + checksum: 10c0/405c3c1a137acda1206380a96993cf2cfd808b3bee1c11c4af47ee0f03a20858497aa53394d6adc5431793c543be5e02010620e871a5ab39d938ae90a54b50f2 languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.7, @babel/helper-create-regexp-features-plugin@npm:^7.25.0, @babel/helper-create-regexp-features-plugin@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.2" +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.7" - regexpu-core: "npm:^5.3.1" + "@babel/helper-annotate-as-pure": "npm:^7.25.7" + regexpu-core: "npm:^6.1.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/85a7e3639c118856fb1113f54fb7e3bf7698171ddfd0cd6fccccd5426b3727bc1434fe7f69090441dcde327feef9de917e00d35e47ab820047057518dd675317 + checksum: 10c0/75919fd5a67cd7be8497b56f7b9ed6b4843cb401956ba8d403aa9ae5b005bc28e35c7f27e704d820edbd1154394ed7a7984d4719916795d89d716f6980fe8bd4 languageName: node linkType: hard @@ -181,223 +181,223 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-member-expression-to-functions@npm:7.24.8" +"@babel/helper-member-expression-to-functions@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-member-expression-to-functions@npm:7.25.7" dependencies: - "@babel/traverse": "npm:^7.24.8" - "@babel/types": "npm:^7.24.8" - checksum: 10c0/7e14a5acc91f6cd26305a4441b82eb6f616bd70b096a4d2099a968f16b26d50207eec0b9ebfc466fefd62bd91587ac3be878117cdfec819b7151911183cb0e5a + "@babel/traverse": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/1e948162ab48d84593a7c6ec9570d14c906146f1697144fc369c59dbeb00e4a062da67dd06cb0d8f98a044cd8389002dcf2ab6f5613d99c35748307846ec63fc 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.7": - version: 7.24.7 - resolution: "@babel/helper-module-imports@npm:7.24.7" +"@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.25.7": + version: 7.25.7 + resolution: "@babel/helper-module-imports@npm:7.25.7" dependencies: - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/97c57db6c3eeaea31564286e328a9fb52b0313c5cfcc7eee4bc226aebcf0418ea5b6fe78673c0e4a774512ec6c86e309d0f326e99d2b37bfc16a25a032498af0 + "@babel/traverse": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/0fd0c3673835e5bf75558e184bcadc47c1f6dd2fe2016d53ebe1e5a6ae931a44e093015c2f9a6651c1a89f25c76d9246710c2b0b460b95ee069c464f2837fa2c languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.24.7, @babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.25.0, @babel/helper-module-transforms@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/helper-module-transforms@npm:7.25.2" +"@babel/helper-module-transforms@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-module-transforms@npm:7.25.7" dependencies: - "@babel/helper-module-imports": "npm:^7.24.7" - "@babel/helper-simple-access": "npm:^7.24.7" - "@babel/helper-validator-identifier": "npm:^7.24.7" - "@babel/traverse": "npm:^7.25.2" + "@babel/helper-module-imports": "npm:^7.25.7" + "@babel/helper-simple-access": "npm:^7.25.7" + "@babel/helper-validator-identifier": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/adaa15970ace0aee5934b5a633789b5795b6229c6a9cf3e09a7e80aa33e478675eee807006a862aa9aa517935d81f88a6db8a9f5936e3a2a40ec75f8062bc329 + checksum: 10c0/f37fa7d1d4df21690535b278468cbd5faf0133a3080f282000cfa4f3ffc9462a1458f866b04b6a2f2d1eec4691236cba9a867da61270dab3ab19846e62f05090 languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" +"@babel/helper-optimise-call-expression@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-optimise-call-expression@npm:7.25.7" dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10c0/ca6a9884705dea5c95a8b3ce132d1e3f2ae951ff74987d400d1d9c215dae9c0f9e29924d8f8e131e116533d182675bc261927be72f6a9a2968eaeeaa51eb1d0f + "@babel/types": "npm:^7.25.7" + checksum: 10c0/19b4cc7e77811b1fedca4928dbc14026afef913c2ba4142e5e110ebdcb5c3b2efc0f0fbee9f362c23a194674147b9d627adea71c289b9be08b9067bc0085308b 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.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.24.8 - resolution: "@babel/helper-plugin-utils@npm:7.24.8" - checksum: 10c0/0376037f94a3bfe6b820a39f81220ac04f243eaee7193774b983e956c1750883ff236b30785795abbcda43fac3ece74750566830c2daa4d6e3870bb0dff34c2d +"@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.25.7, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.25.7 + resolution: "@babel/helper-plugin-utils@npm:7.25.7" + checksum: 10c0/241f8cf3c5b7700e91cab7cfe5b432a3c710ae3cd5bb96dc554da536a6d25f5b9f000cc0c0917501ceb4f76ba92599ee3beb25e10adaf96be59f8df89a842faf languageName: node linkType: hard -"@babel/helper-remap-async-to-generator@npm:^7.24.7, @babel/helper-remap-async-to-generator@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/helper-remap-async-to-generator@npm:7.25.0" +"@babel/helper-remap-async-to-generator@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-remap-async-to-generator@npm:7.25.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-wrap-function": "npm:^7.25.0" - "@babel/traverse": "npm:^7.25.0" + "@babel/helper-annotate-as-pure": "npm:^7.25.7" + "@babel/helper-wrap-function": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/0d17b5f7bb6a607edc9cc62fff8056dd9f341bf2f919884f97b99170d143022a5e7ae57922c4891e4fc360ad291e708d2f8cd8989f1d3cd7a17600159984f5a6 + checksum: 10c0/972d84876adce6ab61c87a2df47e1afc790b73cff0d1767d0a1c5d9f7aa5e91d8c581a272b66b2051a26cfbb167d8a780564705e488e3ce1f477f1c15059bc5f languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.24.7, @babel/helper-replace-supers@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/helper-replace-supers@npm:7.25.0" +"@babel/helper-replace-supers@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-replace-supers@npm:7.25.7" dependencies: - "@babel/helper-member-expression-to-functions": "npm:^7.24.8" - "@babel/helper-optimise-call-expression": "npm:^7.24.7" - "@babel/traverse": "npm:^7.25.0" + "@babel/helper-member-expression-to-functions": "npm:^7.25.7" + "@babel/helper-optimise-call-expression": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/b4b6650ab3d56c39a259367cd97f8df2f21c9cebb3716fea7bca40a150f8847bfb82f481e98927c7c6579b48a977b5a8f77318a1c6aeb497f41ecd6dbc3fdfef + checksum: 10c0/761d64ee74429f7326a6aa65e2cd5bfcb8de9e3bc3f1efb14b8f610d2410f003b0fca52778dc801d49ff8fbc90b057e8f51b27c62b0b05c95eaf23140ca1287b languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-simple-access@npm:7.24.7" +"@babel/helper-simple-access@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-simple-access@npm:7.25.7" dependencies: - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/7230e419d59a85f93153415100a5faff23c133d7442c19e0cd070da1784d13cd29096ee6c5a5761065c44e8164f9f80e3a518c41a0256df39e38f7ad6744fed7 + "@babel/traverse": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/eed1b499bfb4f613c18debd61517e3de77b6da2727ca025aa05ac81599e0269f1dddb5237db04e8bb598115d015874752e0a7f11ff38672d74a4976097417059 languageName: node linkType: hard -"@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" +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.7" dependencies: - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/e3a9b8ac9c262ac976a1bcb5fe59694db5e6f0b4f9e7bdba5c7693b8b5e28113c23bdaa60fe8d3ec32a337091b67720b2053bcb3d5655f5406536c3d0584242b + "@babel/traverse": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/5804adb893849a9d8cfb548e3812566a81d95cb0c9a10d66b52912d13f488e577c33063bf19bc06ac70e6333162a7370d67ba1a1c3544d37fb50d5f4a00db4de languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-string-parser@npm:7.24.8" - checksum: 10c0/6361f72076c17fabf305e252bf6d580106429014b3ab3c1f5c4eb3e6d465536ea6b670cc0e9a637a77a9ad40454d3e41361a2909e70e305116a23d68ce094c08 +"@babel/helper-string-parser@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-string-parser@npm:7.25.7" + checksum: 10c0/73ef2ceb81f8294678a0afe8ab0103729c0370cac2e830e0d5128b03be5f6a2635838af31d391d763e3c5a4460ed96f42fd7c9b552130670d525be665913bc4c languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-validator-identifier@npm:7.24.7" - checksum: 10c0/87ad608694c9477814093ed5b5c080c2e06d44cb1924ae8320474a74415241223cc2a725eea2640dd783ff1e3390e5f95eede978bc540e870053152e58f1d651 +"@babel/helper-validator-identifier@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-validator-identifier@npm:7.25.7" + checksum: 10c0/07438e5bf01ab2882a15027fdf39ac3b0ba1b251774a5130917907014684e2f70fef8fd620137ca062c4c4eedc388508d2ea7a3a7d9936a32785f4fe116c68c0 languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-validator-option@npm:7.24.8" - checksum: 10c0/73db93a34ae89201351288bee7623eed81a54000779462a986105b54ffe82069e764afd15171a428b82e7c7a9b5fec10b5d5603b216317a414062edf5c67a21f +"@babel/helper-validator-option@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-validator-option@npm:7.25.7" + checksum: 10c0/12ed418c8e3ed9ed44c8c80d823f4e42d399b5eb2e423adccb975e31a31a008cd3b5d8eab688b31f740caff4a1bb28fe06ea2fa7d635aee34cc0ad6995d50f0a languageName: node linkType: hard -"@babel/helper-wrap-function@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/helper-wrap-function@npm:7.25.0" +"@babel/helper-wrap-function@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helper-wrap-function@npm:7.25.7" dependencies: - "@babel/template": "npm:^7.25.0" - "@babel/traverse": "npm:^7.25.0" - "@babel/types": "npm:^7.25.0" - checksum: 10c0/d54601a98384c191cbc1ff07b03a19e288ef8d5c6bfafe270b2a303d96e7304eb296002921ed464cc1b105a547d1db146eb86b0be617924dee1ba1b379cdc216 + "@babel/template": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/b5d412f72697f4a4ce4cb9784fbaf82501c63cf95066c0eadd3179e3439cbbf0aa5fa4858d93590083671943cd357aeb87286958df34aa56fdf8a4c9dea39755 languageName: node linkType: hard -"@babel/helpers@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/helpers@npm:7.25.0" +"@babel/helpers@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/helpers@npm:7.25.7" dependencies: - "@babel/template": "npm:^7.25.0" - "@babel/types": "npm:^7.25.0" - checksum: 10c0/b7fe007fc4194268abf70aa3810365085e290e6528dcb9fbbf7a765d43c74b6369ce0f99c5ccd2d44c413853099daa449c9a0123f0b212ac8d18643f2e8174b8 + "@babel/template": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/3b3ae9e373bd785414195ef8f59976a69d5a6ebe0ef2165fdcc5165e5c3ee09e0fcee94bb457df2ddb8c0532e4146d0a9b7a96b3497399a4bff4ffe196b30228 languageName: node linkType: hard -"@babel/highlight@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/highlight@npm:7.24.7" +"@babel/highlight@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/highlight@npm:7.25.7" dependencies: - "@babel/helper-validator-identifier": "npm:^7.24.7" + "@babel/helper-validator-identifier": "npm:^7.25.7" chalk: "npm:^2.4.2" js-tokens: "npm:^4.0.0" picocolors: "npm:^1.0.0" - checksum: 10c0/674334c571d2bb9d1c89bdd87566383f59231e16bcdcf5bb7835babdf03c9ae585ca0887a7b25bdf78f303984af028df52831c7989fecebb5101cc132da9393a + checksum: 10c0/1f5894fdb0a0af6101fb2822369b2eeeae32cbeae2ef73ff73fc6a0a4a20471565cd9cfa589f54ed69df66adeca7c57266031ca9134b7bd244d023a488d419aa 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.25.0, @babel/parser@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/parser@npm:7.25.4" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/parser@npm:7.25.7" dependencies: - "@babel/types": "npm:^7.25.4" + "@babel/types": "npm:^7.25.7" bin: parser: ./bin/babel-parser.js - checksum: 10c0/bdada5662f15d1df11a7266ec3bc9bb769bf3637ecf3d051eafcfc8f576dcf5a3ac1007c5e059db4a1e1387db9ae9caad239fc4f79e4c2200930ed610e779993 + checksum: 10c0/b771469bb6b636c18a8d642b9df3c73913c3860a979591e1a29a98659efd38b81d3e393047b5251fe382d4c82c681c12da9ce91c98d69316d2604d155a214bcf languageName: node linkType: hard -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.3": - version: 7.25.3 - resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.3" +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/traverse": "npm:^7.25.3" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/814b4d3f102e7556a5053d1acf57ef601cfcff39a2c81b8cdc6a5c842e3cb9838f5925d1466a5f1e6416e74c9c83586a3c07fbd7fb8610a396c2becdf9ae5790 + checksum: 10c0/c6ba97c39973897a2ab021c4a77221e1e93e853a5811d498db325da1bd692e41fa521db6d91bb709ccafd4e54ddd00869ffb35846923c3ccd49d46124b316904 languageName: node linkType: hard -"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.25.0" +"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/9645a1f47b3750acadb1353c02e71cc712d072aafe5ce115ed3a886bc14c5d9200cfb0b5b5e60e813baa549b800cf798f8714019fd246c699053cf68c428e426 + checksum: 10c0/ac284868bf410f952c6959b0d77708464127160416f003b05c8127d30e64792d671abc167ebf778b17707e32174223ea8d3ff487276991fa90297d92f0dac6e2 languageName: node linkType: hard -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.0" +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/ed1ce1c90cac46c01825339fd0f2a96fa071b016fb819d8dfaf8e96300eae30e74870cb47e4dc80d4ce2fb287869f102878b4f3b35bc927fec8b1d0d76bcf612 + checksum: 10c0/1bffc0a20c8c82b4c77515eb4c99b961b38184116f008bb42bed4e12d3379ba7b2bc6cf299bcea8118d645bb7a5e0caa83969842f16dd1fce49fb3a050e4ac65 languageName: node linkType: hard -"@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" +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.25.7" dependencies: - "@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" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.7" + "@babel/plugin-transform-optional-chaining": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.13.0 - checksum: 10c0/aeb6e7aa363a47f815cf956ea1053c5dd8b786a17799f065c9688ba4b0051fe7565d258bbe9400bfcbfb3114cb9fda66983e10afe4d750bc70ff75403e15dd36 + checksum: 10c0/32223f012614a0b2657579317ded7d0d09af2aa316285715c5012f974d0f15c2ce2fe0d8e80fdd9bac6c10c21c93cc925a9dfd6c8e21ce7ba1a9fe06a58088b4 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.0" +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/traverse": "npm:^7.25.0" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/45988025537a9d4a27b610fd696a18fd9ba9336621a69b4fb40560eeb10c79657f85c92a37f30c7c8fb29c22970eea0b373315795a891f1a05549a6cfe5a6bfe + checksum: 10c0/aa2ee7a5954d187de6cbcca0e0b64cfb79c4d224c332d1eb1e0e4afd92ef1a1f4bc4af24f66154097ccb348c08121a875456f47baed220b1b9e93584e6a19b65 languageName: node linkType: hard @@ -476,25 +476,25 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-assertions@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-syntax-import-assertions@npm:7.24.7" +"@babel/plugin-syntax-import-assertions@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/b82c53e095274ee71c248551352d73441cf65b3b3fc0107258ba4e9aef7090772a425442b3ed1c396fa207d0efafde8929c87a17d3c885b3ca2021316e87e246 + checksum: 10c0/0fee0d971f3c654749fdf92e09b6556bba26ab014c8e99b7252f6a7f1ca108f17edd7ceefb5401d7b7008e98ab1b6f8c3c6a5db72862e7c7b2fcd649d000d690 languageName: node linkType: hard -"@babel/plugin-syntax-import-attributes@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.7" +"@babel/plugin-syntax-import-attributes@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/eccc54d0f03c96d0eec7a6e2fa124dadbc7298345b62ffc4238f173308c4325b5598f139695ff05a95cf78412ef6903599e4b814496612bf39aad4715a16375b + checksum: 10c0/fe00cdb96fd289ab126830a98e1dcf5ab7b529a6ef1c01a72506b5e7b1197d6e46c3c4d029cd90d1d61eb9a15ef77c282d156d0c02c7e32f168bb09d84150db4 languageName: node linkType: hard @@ -520,14 +520,14 @@ __metadata: languageName: node linkType: hard -"@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" +"@babel/plugin-syntax-jsx@npm:7, @babel/plugin-syntax-jsx@npm:^7.25.7, @babel/plugin-syntax-jsx@npm:^7.7.2": + version: 7.25.7 + resolution: "@babel/plugin-syntax-jsx@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/f44d927a9ae8d5ef016ff5b450e1671e56629ddc12e56b938e41fd46e141170d9dfc9a53d6cb2b9a20a7dd266a938885e6a3981c60c052a2e1daed602ac80e51 + checksum: 10c0/17db499c31fcfaa94d5408726d943955d51d478353d1e2dd84eda6024f7e3d104b9456a77f8aabfae0db7f4dc32f810d08357112f7fcbe305e7c9fcf5b3cac13 languageName: node linkType: hard @@ -619,14 +619,14 @@ __metadata: languageName: node linkType: hard -"@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" +"@babel/plugin-syntax-typescript@npm:^7.25.7, @babel/plugin-syntax-typescript@npm:^7.7.2": + version: 7.25.7 + resolution: "@babel/plugin-syntax-typescript@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/cdabd2e8010fb0ad15b49c2c270efc97c4bfe109ead36c7bbcf22da7a74bc3e49702fc4f22f12d2d6049e8e22a5769258df1fd05f0420ae45e11bdd5bc07805a + checksum: 10c0/ed51fd81a5cf571a89fc4cf4c0e3b0b91285c367237374c133d2e5e718f3963cfa61b81997df39220a8837dc99f9e9a8ab7701d259c09fae379e4843d9db60c2 languageName: node linkType: hard @@ -642,466 +642,466 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-arrow-functions@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.7" +"@babel/plugin-transform-arrow-functions@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6ac05a54e5582f34ac6d5dc26499e227227ec1c7fa6fc8de1f3d40c275f140d3907f79bbbd49304da2d7008a5ecafb219d0b71d78ee3290ca22020d878041245 + checksum: 10c0/c8d75ead93f130bf113b6d29493aca695092661ef039336d2a227169c3b7895aa5e9bcc548c42a95a6eaaaf49e512317b00699940bd40ccefd77443e703d3935 languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.4" +"@babel/plugin-transform-async-generator-functions@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-remap-async-to-generator": "npm:^7.25.0" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-remap-async-to-generator": "npm:^7.25.7" "@babel/plugin-syntax-async-generators": "npm:^7.8.4" - "@babel/traverse": "npm:^7.25.4" + "@babel/traverse": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/efed6f6be90b25ad77c15a622a0dc0b22dbf5d45599c207ab8fbc4e959aef21f574fa467d9cf872e45de664a46c32334e78dee2332d82f5f27e26249a34a0920 + checksum: 10c0/dcdd17d8cafafe0eb2edd0a46a7abe86c72235c957c8eb1157ccadb2b199572d5d1aa36a2d3bce5cb99990f7d3c6290ecf09959c62f3081c4df9ff717a1c84a4 languageName: node linkType: hard -"@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" +"@babel/plugin-transform-async-to-generator@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.25.7" dependencies: - "@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" + "@babel/helper-module-imports": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-remap-async-to-generator": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/83c82e243898875af8457972a26ab29baf8a2078768ee9f35141eb3edff0f84b165582a2ff73e90a9e08f5922bf813dbf15a85c1213654385198f4591c0dc45d + checksum: 10c0/1dbefba9c1455f7a92b8c59a93c622091db945294c936fc2c09b1648308c5b4cb2ecaae92baae0d07a324ab890a8a2ee27ceb046bc120932845d27aede275821 languageName: node linkType: hard -"@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" +"@babel/plugin-transform-block-scoped-functions@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/113e86de4612ae91773ff5cb6b980f01e1da7e26ae6f6012127415d7ae144e74987bc23feb97f63ba4bc699331490ddea36eac004d76a20d5369e4cc6a7f61cd + checksum: 10c0/b1e77492295d1b271ef850a81b0404cf3d0dd6a2bcbeab28a0fd99e61c6de4bda91dff583bb42138eec61bf71282bdd3b1bebcb53b7e373035e77fd6ba66caeb languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/plugin-transform-block-scoping@npm:7.25.0" +"@babel/plugin-transform-block-scoping@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-block-scoping@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/382931c75a5d0ea560387e76cb57b03461300527e4784efcb2fb62f36c1eb0ab331327b6034def256baa0cad9050925a61f9c0d56261b6afd6a29c3065fb0bd4 + checksum: 10c0/b2057e00535cd0e8bd5ee5d4640aa2e952564aeafb1bcf4e7b6de33442422877bb0ca8669ad0a48262ec077271978c61eae87b6b3bc8f472d830fa781d6f7e44 languageName: node linkType: hard -"@babel/plugin-transform-class-properties@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/plugin-transform-class-properties@npm:7.25.4" +"@babel/plugin-transform-class-properties@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-class-properties@npm:7.25.7" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.25.4" - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-create-class-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/0b41bc8a5920d3d17c7c06220b601cf43e0a32ac34f05f05cd0cdf08915e4521b1b707cb1e60942b4fc68a5dfac09f0444a8720e0c72ce76fb039e8ec5263115 + checksum: 10c0/1f41e6934b20ad3e05df63959cff9bc600ff3119153b9acbbd44c1731e7df04866397e6e17799173f4c53cdee6115e155632859aee20bf47ec7dcef3f2168a47 languageName: node linkType: hard -"@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" +"@babel/plugin-transform-class-static-block@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-class-static-block@npm:7.25.7" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-create-class-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.12.0 - checksum: 10c0/b0ade39a3d09dce886f79dbd5907c3d99b48167eddb6b9bbde24a0598129654d7017e611c20494cdbea48b07ac14397cd97ea34e3754bbb2abae4e698128eccb + checksum: 10c0/cbb4b46cbd8ad10106eb2bedb5a0665661a1d1d5b6f3ab565ff454b802dab4718e02b25670fe0d40835494aedb3dc26757c06cc4da6ff3e80291c5f882269bd3 languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/plugin-transform-classes@npm:7.25.4" +"@babel/plugin-transform-classes@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-classes@npm:7.25.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-compilation-targets": "npm:^7.25.2" - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-replace-supers": "npm:^7.25.0" - "@babel/traverse": "npm:^7.25.4" + "@babel/helper-annotate-as-pure": "npm:^7.25.7" + "@babel/helper-compilation-targets": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-replace-supers": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c68424d9dd64860825111aa4a4ed5caf29494b7a02ddb9c36351d768c41e8e05127d89274795cdfcade032d9d299e6c677418259df58c71e68f1741583dcf467 + checksum: 10c0/8121781e1d8acd80e6169019106f73a399475ad9c895c1988a344dfed5a6ddd340938ac55123dc1e423bb8f25f255f5d11031116ad756ba3c314595a97c973af languageName: node linkType: hard -"@babel/plugin-transform-computed-properties@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-computed-properties@npm:7.24.7" +"@babel/plugin-transform-computed-properties@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-computed-properties@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" - "@babel/template": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/template": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/25636dbc1f605c0b8bc60aa58628a916b689473d11551c9864a855142e36742fe62d4a70400ba3b74902338e77fb3d940376c0a0ba154b6b7ec5367175233b49 + checksum: 10c0/7ad0a1c126f50935a02e77d438ebc39078a9d644b3a60de60bec32c5d9f49e7f2b193fcecb8c61bb1bc3cdd4af1e93f72d022d448511fa76a171527c633cd1bf languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/plugin-transform-destructuring@npm:7.24.8" +"@babel/plugin-transform-destructuring@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-destructuring@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/804968c1d5f5072c717505296c1e5d5ec33e90550423de66de82bbcb78157156e8470bbe77a04ab8c710a88a06360a30103cf223ac7eff4829adedd6150de5ce + checksum: 10c0/a563123b2fb267e03aa50104005f00b56226a685938906c42c1b251462e0cc9fc89e587d5656d3324159071eb8ebda8c68a6011f11d5a00fb1436cb5a5411b7b languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.7" +"@babel/plugin-transform-dotall-regex@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.25.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-create-regexp-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/793f14c9494972d294b7e7b97b747f47874b6d57d7804d3443c701becf5db192c9311be6a1835c07664486df1f5c60d33196c36fb7e11a53015e476b4c145b33 + checksum: 10c0/7f1db3ec20b7fae46db4a9c4c257d75418b0896b72c0a3de20b3044f952801480f0a2e75ebb0d64f13e8cd4db0e49aa42c5c0edff372b23c41679b1ea5dd3ed4 languageName: node linkType: hard -"@babel/plugin-transform-duplicate-keys@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.7" +"@babel/plugin-transform-duplicate-keys@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/75ff7ec1117ac500e77bf20a144411d39c0fdd038f108eec061724123ce6d1bb8d5bd27968e466573ee70014f8be0043361cdb0ef388f8a182d1d97ad67e51b9 + checksum: 10c0/b4079981e2db19737a0f1a00254e7388e2d3c01ce36e9fd826e4d86d3c1755339495e29c71fd7c84a068201ec24687328d48f3bf53b32b6d6224f51d9a34da74 languageName: node linkType: hard -"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.25.0" +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.25.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.25.0" - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-create-regexp-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/1c9b57ddd9b33696e88911d0e7975e1573ebc46219c4b30eb1dc746cbb71aedfac6f6dab7fdfdec54dd58f31468bf6ab56b157661ea4ffe58f906d71f89544c8 + checksum: 10c0/e4946090ff6d88d54b78265ee653079ec34c117ac046e22f66f7c4ac44249cdc2dfca385bc5bf4386db668b9948eeb12985589500188bc252e684c7714c31475 languageName: node linkType: hard -"@babel/plugin-transform-dynamic-import@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.7" +"@babel/plugin-transform-dynamic-import@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/eeda48372efd0a5103cb22dadb13563c975bce18ae85daafbb47d57bb9665d187da9d4fe8d07ac0a6e1288afcfcb73e4e5618bf75ff63fddf9736bfbf225203b + checksum: 10c0/c733252ff20a32d9747dd081916270f5a073856597e849a5f458b12f4354499b18714f5e7049e341432851d9975077cb37effcd276c7f816faa6f5ff708dc5e1 languageName: node linkType: hard -"@babel/plugin-transform-exponentiation-operator@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.7" +"@babel/plugin-transform-exponentiation-operator@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.25.7" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/ace3e11c94041b88848552ba8feb39ae4d6cad3696d439ff51445bd2882d8b8775d85a26c2c0edb9b5e38c9e6013cc11b0dea89ec8f93c7d9d7ee95e3645078c + checksum: 10c0/c8537b9f3cddc5a8d3710f6980196dc7a0f4389f8f82617312a5f7b8b15bcd8ddaeba783c687c3ac6031eb0a4ba0bc380a98da6bf7efe98e225602a98ad42a1e languageName: node linkType: hard -"@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" +"@babel/plugin-transform-export-namespace-from@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/4e144d7f1c57bc63b4899dbbbdfed0880f2daa75ea9c7251c7997f106e4b390dc362175ab7830f11358cb21f6b972ca10a43a2e56cd789065f7606b082674c0c + checksum: 10c0/ef61fc5d54c9c8b075cbd9db62beaf295e38e08a1edb1882995105d3e959763be1631f7d7f7cb7461b702ebd0b4a601f2eb2cd6521acaf061310a3a3305fa756 languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-for-of@npm:7.24.7" +"@babel/plugin-transform-for-of@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-for-of@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/77629b1173e55d07416f05ba7353caa09d2c2149da2ca26721ab812209b63689d1be45116b68eadc011c49ced59daf5320835b15245eb7ae93ae0c5e8277cfc0 + checksum: 10c0/08a37a1742368a422d095c998ed76f60f6bf3f9cc060033be121d803fd2dddc08fe543e48ee49c022bdc9ed80893ca79d084958d83d30684178b088774754277 languageName: node linkType: hard -"@babel/plugin-transform-function-name@npm:^7.25.1": - version: 7.25.1 - resolution: "@babel/plugin-transform-function-name@npm:7.25.1" +"@babel/plugin-transform-function-name@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-function-name@npm:7.25.7" dependencies: - "@babel/helper-compilation-targets": "npm:^7.24.8" - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/traverse": "npm:^7.25.1" + "@babel/helper-compilation-targets": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e74912174d5e33d1418b840443c2e226a7b76cc017c1ed20ee30a566e4f1794d4a123be03180da046241576e8b692731807ba1f52608922acf1cb2cb6957593f + checksum: 10c0/ca98e1116c0ada7211ed43e4b7f21ca15f95bbbdad70f2fbe1ec2d90a97daedf9f22fcb0a25c8b164a5e394f509f2e4d1f7609d26dc938a58d37c5ee9b80088a languageName: node linkType: hard -"@babel/plugin-transform-json-strings@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-json-strings@npm:7.24.7" +"@babel/plugin-transform-json-strings@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-json-strings@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-json-strings": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/17c72cd5bf3e90e722aabd333559275f3309e3fa0b9cea8c2944ab83ae01502c71a2be05da5101edc02b3fc8df15a8dbb9b861cbfcc8a52bf5e797cf01d3a40a + checksum: 10c0/aa6e5f65c8a5f2459d7daa9b5b4ff97ff43bab21f4a8513ed84d35300b0323ec542dc101c5f11622e442dfc93b3a229c7f41ebc7645370dfec6d066bda800a0b languageName: node linkType: hard -"@babel/plugin-transform-literals@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/plugin-transform-literals@npm:7.25.2" +"@babel/plugin-transform-literals@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-literals@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/0796883217b0885d37e7f6d350773be349e469a812b6bf11ccf862a6edf65103d3e7c849529d65381b441685c12e756751d8c2489a0fd3f8139bb5ef93185f58 + checksum: 10c0/c2c2488102f33e566f45becdcb632e53bd052ecfb2879deb07a614b3e9437e3b624c3b16d080096d50b0b622edebd03e438acbf9260bcc41167897963f64560e languageName: node linkType: hard -"@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" +"@babel/plugin-transform-logical-assignment-operators@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/dbe882eb9053931f2ab332c50fc7c2a10ef507d6421bd9831adbb4cb7c9f8e1e5fbac4fbd2e007f6a1bf1df1843547559434012f118084dc0bf42cda3b106272 + checksum: 10c0/d610a8a2c1be83e03cce2256f29519e705dc68289c09d67f1f362d1fd80f4b36eaf2affc05710abb53a272895041e24d9e95ec73a516a23a67cb907023fbe37b languageName: node linkType: hard -"@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" +"@babel/plugin-transform-member-expression-literals@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e789ae359bdf2d20e90bedef18dfdbd965c9ebae1cee398474a0c349590fda7c8b874e1a2ceee62e47e5e6ec1730e76b0f24e502164357571854271fc12cc684 + checksum: 10c0/d6936b98ae4d3daed850dc4e064042ea4375f815219ba9d8591373bf1fba4cfdb5be42623ae8882f2d666cc34af650a4855e2a5ad89e3c235d73a6f172f9969c languageName: node linkType: hard -"@babel/plugin-transform-modules-amd@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-modules-amd@npm:7.24.7" +"@babel/plugin-transform-modules-amd@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-modules-amd@npm:7.25.7" dependencies: - "@babel/helper-module-transforms": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6df7de7fce34117ca4b2fa07949b12274c03668cbfe21481c4037b6300796d50ae40f4f170527b61b70a67f26db906747797e30dbd0d9809a441b6e220b5728f + checksum: 10c0/c0bc999206c3834c090e6559a6c8a55d7672d3573104e832223ebe7df99bd1b82fc850e15ba32f512c84b0db1cdb613b66fa60abe9abb9c7e8dcbff91649b356 languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.24.7, @babel/plugin-transform-modules-commonjs@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.8" +"@babel/plugin-transform-modules-commonjs@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.25.7" dependencies: - "@babel/helper-module-transforms": "npm:^7.24.8" - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-simple-access": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-simple-access": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/f1cf552307ebfced20d3907c1dd8be941b277f0364aa655e2b5fee828c84c54065745183104dae86f1f93ea0406db970a463ef7ceaaed897623748e99640e5a7 + checksum: 10c0/2f1c945fc3c9b690b0ddcf2c80156b2e4fbf2cf15aac43ac8fe6e4b34125869528839a53d07c564e62e4aed394ebdc1d2c3b796b547374455522581c11b7599c languageName: node linkType: hard -"@babel/plugin-transform-modules-systemjs@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.0" +"@babel/plugin-transform-modules-systemjs@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.7" dependencies: - "@babel/helper-module-transforms": "npm:^7.25.0" - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-validator-identifier": "npm:^7.24.7" - "@babel/traverse": "npm:^7.25.0" + "@babel/helper-module-transforms": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-validator-identifier": "npm:^7.25.7" + "@babel/traverse": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/fca6198da71237e4bb1274b3b67a0c81d56013c9535361242b6bfa87d70a9597854aadb45d4d8203369be4a655e158be2a5d20af0040b1f8d1bfc47db3ad7b68 + checksum: 10c0/95eaea7082636710c61e49e58b3907e85ec79db4327411d3784f28592509fbe94a53cc3d20a36a1cf245efc6d3f0017eae15b45ffd645c1ab949bb4e1670e6bb languageName: node linkType: hard -"@babel/plugin-transform-modules-umd@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-modules-umd@npm:7.24.7" +"@babel/plugin-transform-modules-umd@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-modules-umd@npm:7.25.7" dependencies: - "@babel/helper-module-transforms": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/7791d290121db210e4338b94b4a069a1a79e4c7a8d7638d8159a97b281851bbed3048dac87a4ae718ad963005e6c14a5d28e6db2eeb2b04e031cee92fb312f85 + checksum: 10c0/8849ab04eecdb73cd37e2d7289449fa5256331832b0304c220b2a6aaa12e2d2dd87684f2813412d1fc5bdb3d6b55cc08c6386d3273fe05a65177c09bee5b6769 languageName: node linkType: hard -"@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" +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.25.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-create-regexp-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/41a0b0f2d0886318237440aa3b489f6d0305361d8671121777d9ff89f9f6de9d0c02ce93625049061426c8994064ef64deae8b819d1b14c00374a6a2336fb5d9 + checksum: 10c0/eb55fec55dc930cd122911f3e4a421320fa8b1b4de85bfd7ef11b46c611ec69b0213c114a6e1c6bc224d6b954ff183a0caa7251267d5258ecc0f00d6d9ca1d52 languageName: node linkType: hard -"@babel/plugin-transform-new-target@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-new-target@npm:7.24.7" +"@babel/plugin-transform-new-target@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-new-target@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/2540808a35e1a978e537334c43dab439cf24c93e7beb213a2e71902f6710e60e0184316643790c0a6644e7a8021e52f7ab8165e6b3e2d6651be07bdf517b67df + checksum: 10c0/8e5dce6d027e0f3fd394578ea1af7f515de157793a15c23a5aad7034a6d8a4005ef280238e67a232bb4dd4fafd3a264fed462deb149128ddd9ce59ff6f575cff languageName: node linkType: hard -"@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" +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/7243c8ff734ed5ef759dd8768773c4b443c12e792727e759a1aec2c7fa2bfdd24f1ecb42e292a7b3d8bd3d7f7b861cf256a8eb4ba144fc9cc463892c303083d9 + checksum: 10c0/b35a96a79ef4895b00e4f758d3185cb17e4fbfada311894ad5f0988a55fc2c21820dc789b26a3cb8fbd620434faa516e52acb6e2da105c2edbd29de8b6b0facf languageName: node linkType: hard -"@babel/plugin-transform-numeric-separator@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.7" +"@babel/plugin-transform-numeric-separator@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e18e09ca5a6342645d00ede477731aa6e8714ff357efc9d7cda5934f1703b3b6fb7d3298dce3ce3ba53e9ff1158eab8f1aadc68874cc21a6099d33a1ca457789 + checksum: 10c0/c028ae89e6b4e1d757f8f1ebcb3b420e6559bb35002728f6f5651d5f669fbf73764adf6e3597908fa12adf8dbae683e5f74b3a7f68e8774a9663c18c0f999539 languageName: node linkType: hard -"@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" +"@babel/plugin-transform-object-rest-spread@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.25.7" dependencies: - "@babel/helper-compilation-targets": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-compilation-targets": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-transform-parameters": "npm:^7.24.7" + "@babel/plugin-transform-parameters": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/9ad64bc003f583030f9da50614b485852f8edac93f8faf5d1cd855201a4852f37c5255ae4daf70dd4375bdd4874e16e39b91f680d4668ec219ba05441ce286eb + checksum: 10c0/e8b978d9d1020452da0d5d92f80fe57e302761dac20137bb8bf863478a4779fcd63d314db89e796125d9d76da2a38f64f012d6e0c4913815951b3eb3fba2feb6 languageName: node linkType: hard -"@babel/plugin-transform-object-super@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-object-super@npm:7.24.7" +"@babel/plugin-transform-object-super@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-object-super@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" - "@babel/helper-replace-supers": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-replace-supers": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/770cebb4b4e1872c216b17069db9a13b87dfee747d359dc56d9fcdd66e7544f92dc6ab1861a4e7e0528196aaff2444e4f17dc84efd8eaf162d542b4ba0943869 + checksum: 10c0/7f2968d4da997101b63fd3b74445c9b16f56bd32cd8a0a16c368af9d3e983e7675c1b05d18601f32307cb06e7d884ee11d13ff18a1f6830c0db243a9a852afab languageName: node linkType: hard -"@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" +"@babel/plugin-transform-optional-catch-binding@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/1e2f10a018f7d03b3bde6c0b70d063df8d5dd5209861d4467726cf834f5e3d354e2276079dc226aa8e6ece35f5c9b264d64b8229a8bb232829c01e561bcfb07a + checksum: 10c0/bb609e5103780be0825a255ffe1fefbb5335aead88a46eecc2257053279ea2c45ff66b0ef1fb54302c8c8c57146e88e52f3ecb62b4c6f619218d7b3843b352d9 languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.24.7, @babel/plugin-transform-optional-chaining@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.8" +"@babel/plugin-transform-optional-chaining@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.7" "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/4ffbe1aad7dec7c9aa2bf6ceb4b2f91f96815b2784f2879bde80e46934f59d64a12cb2c6262e40897c4754d77d2c35d8a5cfed63044fdebf94978b1ed3d14b17 + checksum: 10c0/887441ada6c2bc1b789984b7531d9bc585f335ece99642886d3d9fd8aee7e6b8d4f7ca61d76b5f23477f3aa607284d5056eadaa1eb17e7b39af6b0e834cbe878 languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-parameters@npm:7.24.7" +"@babel/plugin-transform-parameters@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-parameters@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/53bf190d6926771545d5184f1f5f3f5144d0f04f170799ad46a43f683a01fab8d5fe4d2196cf246774530990c31fe1f2b9f0def39f0a5ddbb2340b924f5edf01 + checksum: 10c0/b40ba70278842ce1e800d7ab400df730994941550da547ef453780023bd61a9b8acf4b9fb8419c1b5bcbe09819a1146ff59369db11db07eb71870bef86a12422 languageName: node linkType: hard -"@babel/plugin-transform-private-methods@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/plugin-transform-private-methods@npm:7.25.4" +"@babel/plugin-transform-private-methods@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-private-methods@npm:7.25.7" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.25.4" - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-create-class-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/7abdb427c3984a2c8a2e9d806297d8509b02f78a3501b7760e544be532446e9df328b876daa8fc38718f3dce7ccc45083016ee7aeaab169b81c142bc18700794 + checksum: 10c0/92e076f63f7c4696e1321dafdd56c4212eb41784cdadba0ebc39091f959a76d357c3df61a6c668be81d6b6ad8964ee458e85752ab0c6cfbbaf2066903edda732 languageName: node linkType: hard -"@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" +"@babel/plugin-transform-private-property-in-object@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.25.7" dependencies: - "@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/helper-annotate-as-pure": "npm:^7.25.7" + "@babel/helper-create-class-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c6fa7defb90b1b0ed46f24ff94ff2e77f44c1f478d1090e81712f33cf992dda5ba347016f030082a2f770138bac6f4a9c2c1565e9f767a125901c77dd9c239ba + checksum: 10c0/5ad8832ba54e2079c1f558b8680e170265e3f376424e5fbb75b17b7f08696fb0af6c96d23d92f7df3dcc559f5971a02587281fcec38a853174aa95478565f5fc languageName: node linkType: hard -"@babel/plugin-transform-property-literals@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-property-literals@npm:7.24.7" +"@babel/plugin-transform-property-literals@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-property-literals@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/52564b58f3d111dc02d241d5892a4b01512e98dfdf6ef11b0ed62f8b11b0acacccef0fc229b44114fe8d1a57a8b70780b11bdd18b807d3754a781a07d8f57433 + checksum: 10c0/6d5bccdc772207906666ad5201bd91e4e132e1d806dbcf4163a1d08e18c57cc3795578c4e10596514bcd6afaf9696f478ea4f0dea890176d93b9cb077b9e5c55 languageName: node linkType: hard @@ -1116,244 +1116,245 @@ __metadata: languageName: node linkType: hard -"@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" +"@babel/plugin-transform-react-display-name@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-react-display-name@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c14a07a9e75723c96f1a0a306b8a8e899ff1c6a0cc3d62bcda79bb1b54e4319127b258651c513a1a47da152cdc22e16525525a30ae5933a2980c7036fd0b4d24 + checksum: 10c0/a0c537cc7c328ed7468d3b6a37bf0d9cb15d94afcdf3f2849ce6e5a68494fc61f0fa4fc529482a6b95b00f3c5c734f310bf18085293bff40702789f06c816f36 languageName: node linkType: hard "@babel/plugin-transform-react-inline-elements@npm:^7.21.0": - version: 7.24.7 - resolution: "@babel/plugin-transform-react-inline-elements@npm:7.24.7" + version: 7.25.7 + resolution: "@babel/plugin-transform-react-inline-elements@npm:7.25.7" dependencies: - "@babel/helper-builder-react-jsx": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-builder-react-jsx": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/affe44efc641e5dc4de077db74c80e3dee896a5dfea04491cbd8167ac40dcbb6eaa1ad0ba599e4a85071acdaa08732e7f5d9cf3236a2aa635406c232c8f08236 + checksum: 10c0/de85180c09002083cb330ef28d5b31b44e6ac6565c700b603be76e629f5a92c59ff69f79c08cc1dbd2dd1f271f44fe8d4c751deaf66c059ba721aa3cb43c881e languageName: node linkType: hard -"@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" +"@babel/plugin-transform-react-jsx-development@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.25.7" dependencies: - "@babel/plugin-transform-react-jsx": "npm:^7.24.7" + "@babel/plugin-transform-react-jsx": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/fce647db50f90a5291681f0f97865d9dc76981262dff71d6d0332e724b85343de5860c26f9e9a79e448d61e1d70916b07ce91e8c7f2b80dceb4b16aee41794d8 + checksum: 10c0/a3dc14644d09a6d22875af7b5584393ab53e467e0531cd192fc6242504dacaffa421e89265ba7f84fd4edef2b7b100d2e2ebf092a4dce2b55cf9c5fe29390c18 languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-react-jsx@npm:7.24.7" +"@babel/plugin-transform-react-jsx@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-react-jsx@npm:7.25.7" dependencies: - "@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" + "@babel/helper-annotate-as-pure": "npm:^7.25.7" + "@babel/helper-module-imports": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/plugin-syntax-jsx": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/5c46d2c1c06a30e6bde084839df9cc689bf9c9cb0292105d61c225ca731f64247990724caee7dfc7f817dc964c062e8319e7f05394209590c476b65d75373435 + checksum: 10c0/6766b0357b8bbfcb77fca5350f06cf822c89bbe75ddcaea24614601ef23957504da24e76597d743038ce8fa081373b0663c8ad0c86d7c7226e8185f0680b8b56 languageName: node linkType: hard -"@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" +"@babel/plugin-transform-react-pure-annotations@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.25.7" dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-annotate-as-pure": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/fae517d293d9c93b7b920458c3e4b91cb0400513889af41ba184a5f3acc8bfef27242cc262741bb8f87870df376f1733a0d0f52b966d342e2aaaf5607af8f73d + checksum: 10c0/d92c9b511850fb6dea71966a0d4f313d67e317db7fc3633a7ff2e27d6df2e95cbc91c4c25abdb6c8db651fcda842a0cb7433835a8a9d4a3fdc5d452068428101 languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-regenerator@npm:7.24.7" +"@babel/plugin-transform-regenerator@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-regenerator@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" regenerator-transform: "npm:^0.15.2" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/d2dc2c788fdae9d97217e70d46ba8ca9db0035c398dc3e161552b0c437113719a75c04f201f9c91ddc8d28a1da60d0b0853f616dead98a396abb9c845c44892b + checksum: 10c0/7ee3a57c4050bc908ef7ac392d810826b294970a7182f4ec34a8ca93dbe36deb21bc862616d46a6f3d881d6b5749930e1679e875b638a00866d844a4250df212 languageName: node linkType: hard -"@babel/plugin-transform-reserved-words@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-reserved-words@npm:7.24.7" +"@babel/plugin-transform-reserved-words@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-reserved-words@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/2229de2768615e7f5dc0bbc55bc121b5678fd6d2febd46c74a58e42bb894d74cd5955c805880f4e02d0e1cf94f6886270eda7fafc1be9305a1ec3b9fd1d063f5 + checksum: 10c0/920c98130daff6c1288fb13a9a2d2e45863bba93e619cb88d90e1f5b5cb358a3ee8880a425a3adb1b4bd5dbb6bd0500eea3370fc612633045eec851b08cc586c languageName: node linkType: hard "@babel/plugin-transform-runtime@npm:^7.22.4": - version: 7.25.4 - resolution: "@babel/plugin-transform-runtime@npm:7.25.4" + version: 7.25.7 + resolution: "@babel/plugin-transform-runtime@npm:7.25.7" dependencies: - "@babel/helper-module-imports": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-module-imports": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" babel-plugin-polyfill-corejs2: "npm:^0.4.10" babel-plugin-polyfill-corejs3: "npm:^0.10.6" babel-plugin-polyfill-regenerator: "npm:^0.6.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c08698276596d58bf49e222ead3c414c35d099a7e5a6174b11e2db9b74420e94783ada596820437622c3eccc8852c0e750ad053bd8e775f0050839479ba76e6a + checksum: 10c0/9b2514e9079361ac8e7e500ffd522dad869d61a3894302da7e29bbac80de00276c8a1b4394d1dcf0b51c57b2c854919928df9648be336139fdf1d6ecd6d1bb32 languageName: node linkType: hard -"@babel/plugin-transform-shorthand-properties@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.7" +"@babel/plugin-transform-shorthand-properties@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/41b155bdbb3be66618358488bf7731b3b2e8fff2de3dbfd541847720a9debfcec14db06a117abedd03c9cd786db20a79e2a86509a4f19513f6e1b610520905cf + checksum: 10c0/4250f89a0072f0f400be7a2e3515227b8e2518737899bd57d497e5173284a0e05d812e4a3c219ffcd484e9fa9a01c19fce5acd77bbb898f4d594512c56701eb4 languageName: node linkType: hard -"@babel/plugin-transform-spread@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-spread@npm:7.24.7" +"@babel/plugin-transform-spread@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-spread@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/facba1553035f76b0d2930d4ada89a8cd0f45b79579afd35baefbfaf12e3b86096995f4b0c402cf9ee23b3f2ea0a4460c3b1ec0c192d340962c948bb223d4e66 + checksum: 10c0/258bd1b52388cd7425d0ae25fa39538734f7540ea503a1d8a72211d33f6f214cb4e3b73d6cd03016cbcff5d41169f1e578b9ea331965ad224d223591983e90a7 languageName: node linkType: hard -"@babel/plugin-transform-sticky-regex@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.7" +"@babel/plugin-transform-sticky-regex@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/5a74ed2ed0a3ab51c3d15fcaf09d9e2fe915823535c7a4d7b019813177d559b69677090e189ec3d5d08b619483eb5ad371fbcfbbff5ace2a76ba33ee566a1109 + checksum: 10c0/0e466cfc3ca1e0db4bb11eb630215b0e1f43066d7678325e5ddadcf5a118b2351a528f67205729c32ac5b78ab68ab7f40517dd33bcb1fb6b456509f5f54ce097 languageName: node linkType: hard -"@babel/plugin-transform-template-literals@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-template-literals@npm:7.24.7" +"@babel/plugin-transform-template-literals@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-template-literals@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/3630f966257bcace122f04d3157416a09d40768c44c3a800855da81146b009187daa21859d1c3b7d13f4e19e8888e60613964b175b2275d451200fb6d8d6cfe6 + checksum: 10c0/a3455303b6841cb536ac66d1a2d03c194b9f371519482d8d1e8edbd33bf5ca7cdd5db1586b2b0ea5f909ebf74a0eafacf0fb28d257e4905445282dcdccfa6139 languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.8" +"@babel/plugin-transform-typeof-symbol@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/2f570a4fbbdc5fd85f48165a97452826560051e3b8efb48c3bb0a0a33ee8485633439e7b71bfe3ef705583a1df43f854f49125bd759abdedc195b2cf7e60012a + checksum: 10c0/ce1a0744a900b05de1372a70508c4148f17eb941c482da26eb369b9f0347570dce45470c8a86d907bc3a0443190344da1e18489ecfecb30388ab6178e8a9916b languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-typescript@npm:7.24.7" +"@babel/plugin-transform-typescript@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-typescript@npm:7.25.7" dependencies: - "@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" + "@babel/helper-annotate-as-pure": "npm:^7.25.7" + "@babel/helper-create-class-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.25.7" + "@babel/plugin-syntax-typescript": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e8dacdc153a4c4599014b66eb01b94e3dc933d58d4f0cc3039c1a8f432e77b9df14f34a61964e014b975bf466f3fefd8c4768b3e887d3da1be9dc942799bdfdf + checksum: 10c0/5fa839b9560221698edff5e00b5cccc658c7875efaa7971c66d478f5b026770f12dd47b1be024463a44f9e29b4e14e8ddddbf4a2b324b0b94f58370dd5ae7195 languageName: node linkType: hard -"@babel/plugin-transform-unicode-escapes@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.7" +"@babel/plugin-transform-unicode-escapes@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.25.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/8b18e2e66af33471a6971289492beff5c240e56727331db1d34c4338a6a368a82a7ed6d57ec911001b6d65643aed76531e1e7cac93265fb3fb2717f54d845e69 + checksum: 10c0/8b1f71fda0a832c6e26ba4c00f99e9033e6f9b36ced542a512921f4ad861a70e2fec2bd54a91a5ca2efa46aaa8c8893e4c602635c4ef172bd3ed6eef3178c70b languageName: node linkType: hard -"@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" +"@babel/plugin-transform-unicode-property-regex@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.25.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-create-regexp-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/bc57656eb94584d1b74a385d378818ac2b3fca642e3f649fead8da5fb3f9de22f8461185936915dfb33d5a9104e62e7a47828331248b09d28bb2d59e9276de3e + checksum: 10c0/b4bfcf7529138d00671bf5cdfe606603d52cfe57ec1be837da57683f404fc0b0c171834a02515eb03379e5c806121866d097b90e31cb437d21d0ea59368ad82b languageName: node linkType: hard -"@babel/plugin-transform-unicode-regex@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.7" +"@babel/plugin-transform-unicode-regex@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.25.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-create-regexp-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/83f72a345b751566b601dc4d07e9f2c8f1bc0e0c6f7abb56ceb3095b3c9d304de73f85f2f477a09f8cc7edd5e65afd0ff9e376cdbcbea33bc0c28f3705b38fd9 + checksum: 10c0/73ae34c02ea8b7ac7e4efa690f8c226089c074e3fef658d2a630ad898a93550d84146ce05e073c271c8b2bbba61cbbfd5a2002a7ea940dcad3274e5b5dcb6bcf languageName: node linkType: hard -"@babel/plugin-transform-unicode-sets-regex@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.25.4" +"@babel/plugin-transform-unicode-sets-regex@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.25.7" dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.25.2" - "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-create-regexp-features-plugin": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/f65749835a98d8d6242e961f9276bdcdb09020e791d151ccc145acaca9a66f025b2c7cb761104f139180d35eb066a429596ee6edece81f5fd9244e0edb97d7ec + checksum: 10c0/39e45ae3db7adfc3457b1d6ba5608ffbace957ad019785967e5357a6639f261765bda12363f655d39265f5a2834af26327037751420191d0b73152ccc7ce3c35 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.25.4 - resolution: "@babel/preset-env@npm:7.25.4" - dependencies: - "@babel/compat-data": "npm:^7.25.4" - "@babel/helper-compilation-targets": "npm:^7.25.2" - "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-validator-option": "npm:^7.24.8" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.25.3" - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "npm:^7.25.0" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.25.0" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.7" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.25.0" + version: 7.25.7 + resolution: "@babel/preset-env@npm:7.25.7" + dependencies: + "@babel/compat-data": "npm:^7.25.7" + "@babel/helper-compilation-targets": "npm:^7.25.7" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-validator-option": "npm:^7.25.7" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.25.7" + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "npm:^7.25.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.25.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.25.7" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.25.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.7" - "@babel/plugin-syntax-import-attributes": "npm:^7.24.7" + "@babel/plugin-syntax-import-assertions": "npm:^7.25.7" + "@babel/plugin-syntax-import-attributes": "npm:^7.25.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" @@ -1365,64 +1366,64 @@ __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.7" - "@babel/plugin-transform-async-generator-functions": "npm:^7.25.4" - "@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.25.0" - "@babel/plugin-transform-class-properties": "npm:^7.25.4" - "@babel/plugin-transform-class-static-block": "npm:^7.24.7" - "@babel/plugin-transform-classes": "npm:^7.25.4" - "@babel/plugin-transform-computed-properties": "npm:^7.24.7" - "@babel/plugin-transform-destructuring": "npm:^7.24.8" - "@babel/plugin-transform-dotall-regex": "npm:^7.24.7" - "@babel/plugin-transform-duplicate-keys": "npm:^7.24.7" - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "npm:^7.25.0" - "@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.25.1" - "@babel/plugin-transform-json-strings": "npm:^7.24.7" - "@babel/plugin-transform-literals": "npm:^7.25.2" - "@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.8" - "@babel/plugin-transform-modules-systemjs": "npm:^7.25.0" - "@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.8" - "@babel/plugin-transform-parameters": "npm:^7.24.7" - "@babel/plugin-transform-private-methods": "npm:^7.25.4" - "@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.8" - "@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.25.4" + "@babel/plugin-transform-arrow-functions": "npm:^7.25.7" + "@babel/plugin-transform-async-generator-functions": "npm:^7.25.7" + "@babel/plugin-transform-async-to-generator": "npm:^7.25.7" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.25.7" + "@babel/plugin-transform-block-scoping": "npm:^7.25.7" + "@babel/plugin-transform-class-properties": "npm:^7.25.7" + "@babel/plugin-transform-class-static-block": "npm:^7.25.7" + "@babel/plugin-transform-classes": "npm:^7.25.7" + "@babel/plugin-transform-computed-properties": "npm:^7.25.7" + "@babel/plugin-transform-destructuring": "npm:^7.25.7" + "@babel/plugin-transform-dotall-regex": "npm:^7.25.7" + "@babel/plugin-transform-duplicate-keys": "npm:^7.25.7" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "npm:^7.25.7" + "@babel/plugin-transform-dynamic-import": "npm:^7.25.7" + "@babel/plugin-transform-exponentiation-operator": "npm:^7.25.7" + "@babel/plugin-transform-export-namespace-from": "npm:^7.25.7" + "@babel/plugin-transform-for-of": "npm:^7.25.7" + "@babel/plugin-transform-function-name": "npm:^7.25.7" + "@babel/plugin-transform-json-strings": "npm:^7.25.7" + "@babel/plugin-transform-literals": "npm:^7.25.7" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.25.7" + "@babel/plugin-transform-member-expression-literals": "npm:^7.25.7" + "@babel/plugin-transform-modules-amd": "npm:^7.25.7" + "@babel/plugin-transform-modules-commonjs": "npm:^7.25.7" + "@babel/plugin-transform-modules-systemjs": "npm:^7.25.7" + "@babel/plugin-transform-modules-umd": "npm:^7.25.7" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.25.7" + "@babel/plugin-transform-new-target": "npm:^7.25.7" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.25.7" + "@babel/plugin-transform-numeric-separator": "npm:^7.25.7" + "@babel/plugin-transform-object-rest-spread": "npm:^7.25.7" + "@babel/plugin-transform-object-super": "npm:^7.25.7" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.25.7" + "@babel/plugin-transform-optional-chaining": "npm:^7.25.7" + "@babel/plugin-transform-parameters": "npm:^7.25.7" + "@babel/plugin-transform-private-methods": "npm:^7.25.7" + "@babel/plugin-transform-private-property-in-object": "npm:^7.25.7" + "@babel/plugin-transform-property-literals": "npm:^7.25.7" + "@babel/plugin-transform-regenerator": "npm:^7.25.7" + "@babel/plugin-transform-reserved-words": "npm:^7.25.7" + "@babel/plugin-transform-shorthand-properties": "npm:^7.25.7" + "@babel/plugin-transform-spread": "npm:^7.25.7" + "@babel/plugin-transform-sticky-regex": "npm:^7.25.7" + "@babel/plugin-transform-template-literals": "npm:^7.25.7" + "@babel/plugin-transform-typeof-symbol": "npm:^7.25.7" + "@babel/plugin-transform-unicode-escapes": "npm:^7.25.7" + "@babel/plugin-transform-unicode-property-regex": "npm:^7.25.7" + "@babel/plugin-transform-unicode-regex": "npm:^7.25.7" + "@babel/plugin-transform-unicode-sets-regex": "npm:^7.25.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.6" babel-plugin-polyfill-regenerator: "npm:^0.6.1" - core-js-compat: "npm:^3.37.1" + core-js-compat: "npm:^3.38.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/ed210a1974b5a1e7f80a933c87253907ec869457cea900bc97892642fa9a690c47627a9bac08a7c9495deb992a2b15f308ffca2741e1876ba47172c96fa27e14 + checksum: 10c0/bf704a06a69420250c1de2b126cd5c859a851002c2fb2cce0910cd85a8e6755b9b31577021e94feb7e1e53519923726349aaf07580923928791583db61438fb8 languageName: node linkType: hard @@ -1440,40 +1441,33 @@ __metadata: linkType: hard "@babel/preset-react@npm:^7.12.5, @babel/preset-react@npm:^7.22.3": - version: 7.24.7 - resolution: "@babel/preset-react@npm:7.24.7" + version: 7.25.7 + resolution: "@babel/preset-react@npm:7.25.7" dependencies: - "@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" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-validator-option": "npm:^7.25.7" + "@babel/plugin-transform-react-display-name": "npm:^7.25.7" + "@babel/plugin-transform-react-jsx": "npm:^7.25.7" + "@babel/plugin-transform-react-jsx-development": "npm:^7.25.7" + "@babel/plugin-transform-react-pure-annotations": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/9658b685b25cedaadd0b65c4e663fbc7f57394b5036ddb4c99b1a75b0711fb83292c1c625d605c05b73413fc7a6dc20e532627f6a39b6dc8d4e00415479b054c + checksum: 10c0/b133b1a2f46c70a337d8b1ef442e09e3dbdaecb0d6bed8f1cb64dfddc31c16e248b017385ab909caeebd8462111c9c0e1c5409deb10f2be5cb5bcfdaa4d27718 languageName: node linkType: hard "@babel/preset-typescript@npm:^7.21.5": - version: 7.24.7 - resolution: "@babel/preset-typescript@npm:7.24.7" + version: 7.25.7 + resolution: "@babel/preset-typescript@npm:7.25.7" dependencies: - "@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" + "@babel/helper-plugin-utils": "npm:^7.25.7" + "@babel/helper-validator-option": "npm:^7.25.7" + "@babel/plugin-syntax-jsx": "npm:^7.25.7" + "@babel/plugin-transform-modules-commonjs": "npm:^7.25.7" + "@babel/plugin-transform-typescript": "npm:^7.25.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/986bc0978eedb4da33aba8e1e13a3426dd1829515313b7e8f4ba5d8c18aff1663b468939d471814e7acf4045d326ae6cff37239878d169ac3fe53a8fde71f8ee - languageName: node - linkType: hard - -"@babel/regjsgen@npm:^0.8.0": - version: 0.8.0 - resolution: "@babel/regjsgen@npm:0.8.0" - checksum: 10c0/4f3ddd8c7c96d447e05c8304c1d5ba3a83fcabd8a716bc1091c2f31595cdd43a3a055fff7cb5d3042b8cb7d402d78820fcb4e05d896c605a7d8bcf30f2424c4a + checksum: 10c0/8dc1258e3c5230bbe42ff9811f08924509238e6bd32fa0b7b0c0a6c5e1419512a8e1f733e1b114454d367b7c164beca2cf33acf2ed9e0d99be010c1c5cdbef0c languageName: node linkType: hard @@ -1487,48 +1481,48 @@ __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.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.25.6 - resolution: "@babel/runtime@npm:7.25.6" + version: 7.25.7 + resolution: "@babel/runtime@npm:7.25.7" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/d6143adf5aa1ce79ed374e33fdfd74fa975055a80bc6e479672ab1eadc4e4bfd7484444e17dd063a1d180e051f3ec62b357c7a2b817e7657687b47313158c3d2 + checksum: 10c0/86b7829d2fc9343714a9afe92757cf96c4dc799006ca61d73cda62f4b9e29bfa1ce36794955bc6cb4c188f5b10db832c949339895e1bbe81a69022d9d578ce29 languageName: node linkType: hard -"@babel/template@npm:^7.24.7, @babel/template@npm:^7.25.0, @babel/template@npm:^7.3.3": - version: 7.25.0 - resolution: "@babel/template@npm:7.25.0" +"@babel/template@npm:^7.25.7, @babel/template@npm:^7.3.3": + version: 7.25.7 + resolution: "@babel/template@npm:7.25.7" dependencies: - "@babel/code-frame": "npm:^7.24.7" - "@babel/parser": "npm:^7.25.0" - "@babel/types": "npm:^7.25.0" - checksum: 10c0/4e31afd873215744c016e02b04f43b9fa23205d6d0766fb2e93eb4091c60c1b88897936adb895fb04e3c23de98dfdcbe31bc98daaa1a4e0133f78bb948e1209b + "@babel/code-frame": "npm:^7.25.7" + "@babel/parser": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" + checksum: 10c0/8ae9e36e4330ee83d4832531d1d9bec7dc2ef6a2a8afa1ef1229506fd60667abcb17f306d1c3d7e582251270597022990c845d5d69e7add70a5aea66720decb9 languageName: node linkType: hard -"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.1, @babel/traverse@npm:^7.25.2, @babel/traverse@npm:^7.25.3, @babel/traverse@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/traverse@npm:7.25.4" +"@babel/traverse@npm:7, @babel/traverse@npm:^7.25.7": + version: 7.25.7 + resolution: "@babel/traverse@npm:7.25.7" dependencies: - "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.25.4" - "@babel/parser": "npm:^7.25.4" - "@babel/template": "npm:^7.25.0" - "@babel/types": "npm:^7.25.4" + "@babel/code-frame": "npm:^7.25.7" + "@babel/generator": "npm:^7.25.7" + "@babel/parser": "npm:^7.25.7" + "@babel/template": "npm:^7.25.7" + "@babel/types": "npm:^7.25.7" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10c0/37c9b49b277e051fe499ef5f6f217370c4f648d6370564d70b5e6beb2da75bfda6d7dab1d39504d89e9245448f8959bc1a5880d2238840cdc3979b35338ed0f5 + checksum: 10c0/75d73e52c507a7a7a4c7971d6bf4f8f26fdd094e0d3a0193d77edf6a5efa36fc3db91ec5cc48e8b94e6eb5d5ad21af0a1040e71309172851209415fd105efb1a 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.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.4, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": - version: 7.25.4 - resolution: "@babel/types@npm:7.25.4" +"@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.25.7, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": + version: 7.25.7 + resolution: "@babel/types@npm:7.25.7" dependencies: - "@babel/helper-string-parser": "npm:^7.24.8" - "@babel/helper-validator-identifier": "npm:^7.24.7" + "@babel/helper-string-parser": "npm:^7.25.7" + "@babel/helper-validator-identifier": "npm:^7.25.7" to-fast-properties: "npm:^2.0.0" - checksum: 10c0/9aa25dfcd89cc4e4dde3188091c34398a005a49e2c2b069d0367b41e1122c91e80fd92998c52a90f2fb500f7e897b6090ec8be263d9cb53d0d75c756f44419f2 + checksum: 10c0/e03e1e2e08600fa1e8eb90632ac9c253dd748176c8d670d85f85b0dc83a0573b26ae748a1cbcb81f401903a3d95f43c3f4f8d516a5ed779929db27de56289633 languageName: node linkType: hard @@ -1763,9 +1757,9 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-light-dark-function@npm:^2.0.2": - version: 2.0.2 - resolution: "@csstools/postcss-light-dark-function@npm:2.0.2" +"@csstools/postcss-light-dark-function@npm:^2.0.4": + version: 2.0.4 + resolution: "@csstools/postcss-light-dark-function@npm:2.0.4" dependencies: "@csstools/css-parser-algorithms": "npm:^3.0.1" "@csstools/css-tokenizer": "npm:^3.0.1" @@ -1773,7 +1767,7 @@ __metadata: "@csstools/utilities": "npm:^2.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/f8973c435868998e5d6af1fc0c35b27bbf65fa9d0c35f5055c689b8ee2807a16802044e296f7def39a7253ae544fb49559e8273ee22eb4e21845aa980a1bc82b + checksum: 10c0/0176422ad9747953964b1ceff002df1ecb1952ebc481db6192070d68777135b582ea6fd32ae819b9c64c96cb9170bd6907c647c85b48daa4984b7ed3d7f9bccb languageName: node linkType: hard @@ -5697,17 +5691,17 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1, browserslist@npm:^4.23.3": - version: 4.23.3 - resolution: "browserslist@npm:4.23.3" +"browserslist@npm:^4.0.0, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1, browserslist@npm:^4.23.3, browserslist@npm:^4.24.0": + version: 4.24.0 + resolution: "browserslist@npm:4.24.0" dependencies: - caniuse-lite: "npm:^1.0.30001646" - electron-to-chromium: "npm:^1.5.4" + caniuse-lite: "npm:^1.0.30001663" + electron-to-chromium: "npm:^1.5.28" node-releases: "npm:^2.0.18" update-browserslist-db: "npm:^1.1.0" bin: browserslist: cli.js - checksum: 10c0/3063bfdf812815346447f4796c8f04601bf5d62003374305fd323c2a463e42776475bcc5309264e39bcf9a8605851e53560695991a623be988138b3ff8c66642 + checksum: 10c0/95e76ad522753c4c470427f6e3c8a4bb5478ff448841e22b3d3e53f89ecaf17b6984666d6c7e715c370f1e7fa0cf684f42e34e554236a8b2fab38ea76b9e4c52 languageName: node linkType: hard @@ -5909,10 +5903,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001599, caniuse-lite@npm:^1.0.30001646": - version: 1.0.30001651 - resolution: "caniuse-lite@npm:1.0.30001651" - checksum: 10c0/7821278952a6dbd17358e5d08083d258f092e2a530f5bc1840657cb140fbbc5ec44293bc888258c44a18a9570cde149ed05819ac8320b9710cf22f699891e6ad +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001599, caniuse-lite@npm:^1.0.30001663": + version: 1.0.30001666 + resolution: "caniuse-lite@npm:1.0.30001666" + checksum: 10c0/2d49e9be676233c24717f12aad3d01b3e5f902b457fe1deefaa8d82e64786788a8f79381ae437c61b50e15c9aea8aeb59871b1d54cb4c28b9190d53d292e2339 languageName: node linkType: hard @@ -6422,7 +6416,7 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.37.1, core-js-compat@npm:^3.38.0": +"core-js-compat@npm:^3.38.0, core-js-compat@npm:^3.38.1": version: 3.38.1 resolution: "core-js-compat@npm:3.38.1" dependencies: @@ -7484,10 +7478,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.4": - version: 1.5.7 - resolution: "electron-to-chromium@npm:1.5.7" - checksum: 10c0/be4460bbe3d2186a16d53a03da67fde6fd06ad41943553ce517a45d52e03424732a982f75528e8a2d5fb042d6afde64186aa482caec0fb925daa5a74cf5ef060 +"electron-to-chromium@npm:^1.5.28": + version: 1.5.31 + resolution: "electron-to-chromium@npm:1.5.31" + checksum: 10c0/e8aecd88c4c6d50a9d459b4b222865b855bab8f1b52e82913804e18b7884f2887bd76c61b3aa08c2ccbdcda098dd8486443f75bf770f0138f21dd9e63548fca7 languageName: node linkType: hard @@ -11214,21 +11208,12 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:^2.5.1": - version: 2.5.2 - resolution: "jsesc@npm:2.5.2" - bin: - jsesc: bin/jsesc - checksum: 10c0/dbf59312e0ebf2b4405ef413ec2b25abb5f8f4d9bc5fb8d9f90381622ebca5f2af6a6aa9a8578f65903f9e33990a6dc798edd0ce5586894bf0e9e31803a1de88 - languageName: node - linkType: hard - -"jsesc@npm:~0.5.0": - version: 0.5.0 - resolution: "jsesc@npm:0.5.0" +"jsesc@npm:^3.0.2, jsesc@npm:~3.0.2": + version: 3.0.2 + resolution: "jsesc@npm:3.0.2" bin: jsesc: bin/jsesc - checksum: 10c0/f93792440ae1d80f091b65f8ceddf8e55c4bb7f1a09dee5dcbdb0db5612c55c0f6045625aa6b7e8edb2e0a4feabd80ee48616dbe2d37055573a84db3d24f96d9 + checksum: 10c0/ef22148f9e793180b14d8a145ee6f9f60f301abf443288117b4b6c53d0ecd58354898dc506ccbb553a5f7827965cd38bc5fb726575aae93c5e8915e2de8290e1 languageName: node linkType: hard @@ -13945,8 +13930,8 @@ __metadata: linkType: hard "postcss-preset-env@npm:^10.0.0": - version: 10.0.3 - resolution: "postcss-preset-env@npm:10.0.3" + version: 10.0.5 + resolution: "postcss-preset-env@npm:10.0.5" dependencies: "@csstools/postcss-cascade-layers": "npm:^5.0.0" "@csstools/postcss-color-function": "npm:^4.0.2" @@ -13960,7 +13945,7 @@ __metadata: "@csstools/postcss-ic-unit": "npm:^4.0.0" "@csstools/postcss-initial": "npm:^2.0.0" "@csstools/postcss-is-pseudo-class": "npm:^5.0.0" - "@csstools/postcss-light-dark-function": "npm:^2.0.2" + "@csstools/postcss-light-dark-function": "npm:^2.0.4" "@csstools/postcss-logical-float-and-clear": "npm:^3.0.0" "@csstools/postcss-logical-overflow": "npm:^2.0.0" "@csstools/postcss-logical-overscroll-behavior": "npm:^2.0.0" @@ -14011,7 +13996,7 @@ __metadata: postcss-selector-not: "npm:^8.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/da42caa2aab4d825fddfde00ebe2416d338c7b9a6f79a68840297888a8384f85991991c3fa10cf2d359fb230c885375f5cebd7bd63972725cd2a596d218f8b6a + checksum: 10c0/db5eb1175cb26bed3f1a4c47acc67935ffc784520321470520e59de366ac6f91be1e609fe36056af707ed20f7910721287cff0fae416c437dd3e944de13ffd05 languageName: node linkType: hard @@ -15066,12 +15051,12 @@ __metadata: languageName: node linkType: hard -"regenerate-unicode-properties@npm:^10.1.0": - version: 10.1.1 - resolution: "regenerate-unicode-properties@npm:10.1.1" +"regenerate-unicode-properties@npm:^10.2.0": + version: 10.2.0 + resolution: "regenerate-unicode-properties@npm:10.2.0" dependencies: regenerate: "npm:^1.4.2" - checksum: 10c0/89adb5ee5ba081380c78f9057c02e156a8181969f6fcca72451efc45612e0c3df767b4333f8d8479c274d9c6fe52ec4854f0d8a22ef95dccbe87da8e5f2ac77d + checksum: 10c0/5510785eeaf56bbfdf4e663d6753f125c08d2a372d4107bc1b756b7bf142e2ed80c2733a8b54e68fb309ba37690e66a0362699b0e21d5c1f0255dea1b00e6460 languageName: node linkType: hard @@ -15134,28 +15119,35 @@ __metadata: languageName: node linkType: hard -"regexpu-core@npm:^5.3.1": - version: 5.3.2 - resolution: "regexpu-core@npm:5.3.2" +"regexpu-core@npm:^6.1.1": + version: 6.1.1 + resolution: "regexpu-core@npm:6.1.1" dependencies: - "@babel/regjsgen": "npm:^0.8.0" regenerate: "npm:^1.4.2" - regenerate-unicode-properties: "npm:^10.1.0" - regjsparser: "npm:^0.9.1" + regenerate-unicode-properties: "npm:^10.2.0" + regjsgen: "npm:^0.8.0" + regjsparser: "npm:^0.11.0" unicode-match-property-ecmascript: "npm:^2.0.0" unicode-match-property-value-ecmascript: "npm:^2.1.0" - checksum: 10c0/7945d5ab10c8bbed3ca383d4274687ea825aee4ab93a9c51c6e31e1365edd5ea807f6908f800ba017b66c462944ba68011164e7055207747ab651f8111ef3770 + checksum: 10c0/07d49697e20f9b65977535abba4858b7f5171c13f7c366be53ec1886d3d5f69f1b98cc6a6e63cf271adda077c3366a4c851c7473c28bbd69cf5a6b6b008efc3e languageName: node linkType: hard -"regjsparser@npm:^0.9.1": - version: 0.9.1 - resolution: "regjsparser@npm:0.9.1" +"regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "regjsgen@npm:0.8.0" + checksum: 10c0/44f526c4fdbf0b29286101a282189e4dbb303f4013cf3fea058668d96d113b9180d3d03d1e13f6d4cbde38b7728bf951aecd9dc199938c080093a9a6f0d7a6bd + languageName: node + linkType: hard + +"regjsparser@npm:^0.11.0": + version: 0.11.0 + resolution: "regjsparser@npm:0.11.0" dependencies: - jsesc: "npm:~0.5.0" + jsesc: "npm:~3.0.2" bin: regjsparser: bin/parser - checksum: 10c0/fe44fcf19a99fe4f92809b0b6179530e5ef313ff7f87df143b08ce9a2eb3c4b6189b43735d645be6e8f4033bfb015ed1ca54f0583bc7561bed53fd379feb8225 + checksum: 10c0/155143a8f2c95e3170df4fff10ddf3f16a351b5d2b8cbb257e9f4a50abb9a980a28af0936b5bf850fee767537ffa8eb77c6b211fe8be19834dbe584dfd950c62 languageName: node linkType: hard @@ -17414,22 +17406,22 @@ __metadata: linkType: hard "typescript@npm:5, typescript@npm:^5.0.4": - version: 5.5.4 - resolution: "typescript@npm:5.5.4" + version: 5.6.2 + resolution: "typescript@npm:5.6.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/422be60f89e661eab29ac488c974b6cc0a660fb2228003b297c3d10c32c90f3bcffc1009b43876a082515a3c376b1eefcce823d6e78982e6878408b9a923199c + checksum: 10c0/3ed8297a8c7c56b7fec282532503d1ac795239d06e7c4966b42d4330c6cf433a170b53bcf93a130a7f14ccc5235de5560df4f1045eb7f3550b46ebed16d3c5e5 languageName: node linkType: hard "typescript@patch:typescript@npm%3A5#optional!builtin, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin": - version: 5.5.4 - resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin::version=5.5.4&hash=379a07" + version: 5.6.2 + resolution: "typescript@patch:typescript@npm%3A5.6.2#optional!builtin::version=5.6.2&hash=8c6c40" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/73409d7b9196a5a1217b3aaad929bf76294d3ce7d6e9766dd880ece296ee91cf7d7db6b16c6c6c630ee5096eccde726c0ef17c7dfa52b01a243e57ae1f09ef07 + checksum: 10c0/94eb47e130d3edd964b76da85975601dcb3604b0c848a36f63ac448d0104e93819d94c8bdf6b07c00120f2ce9c05256b8b6092d23cf5cf1c6fa911159e4d572f languageName: node linkType: hard