diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 849789fe2c..e638b9c548 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -15,6 +15,8 @@ // to `null` after any other rule set it to something. dependencyDashboardHeader: 'This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more. Before approving any upgrade: read the description and comments in the [`renovate.json5` file](https://github.com/mastodon/mastodon/blob/main/.github/renovate.json5).', postUpdateOptions: ['yarnDedupeHighest'], + // The types are now included in recent versions,we ignore them here until we upgrade and remove the dependency + ignoreDeps: ['@types/emoji-mart'], packageRules: [ { // Require Dependency Dashboard Approval for major version bumps of these node packages diff --git a/Gemfile.lock b/Gemfile.lock index 89397cb8bc..b949c7ec54 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -94,7 +94,7 @@ GEM ast (2.4.3) attr_required (1.0.2) aws-eventstream (1.3.2) - aws-partitions (1.1066.0) + aws-partitions (1.1080.0) aws-sdk-core (3.215.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) @@ -126,7 +126,7 @@ GEM blurhash (0.1.8) bootsnap (1.18.4) msgpack (~> 1.2) - brakeman (7.0.0) + brakeman (7.0.1) racc browser (6.2.0) brpoplpush-redis_script (0.1.3) @@ -194,7 +194,7 @@ GEM devise_pam_authenticatable2 (9.2.0) devise (>= 4.0.0) rpam2 (~> 4.0) - diff-lcs (1.6.0) + diff-lcs (1.6.1) discard (1.4.0) activerecord (>= 4.2, < 9.0) docile (1.4.1) @@ -266,10 +266,10 @@ GEM raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) - google-protobuf (4.30.1) + google-protobuf (4.30.2) bigdecimal rake (>= 13) - googleapis-common-protos-types (1.18.0) + googleapis-common-protos-types (1.19.0) google-protobuf (>= 3.18, < 5.a) haml (6.3.0) temple (>= 0.8.2) @@ -328,7 +328,7 @@ GEM activesupport (>= 3.0) nokogiri (>= 1.6) io-console (0.8.0) - irb (1.15.1) + irb (1.15.2) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) @@ -426,7 +426,7 @@ GEM mime-types (3.6.2) logger mime-types-data (~> 3.2015) - mime-types-data (3.2025.0318) + mime-types-data (3.2025.0402) mini_mime (1.1.5) mini_portile2 (2.8.8) minitest (5.25.5) @@ -569,7 +569,7 @@ GEM opentelemetry-instrumentation-redis (0.26.1) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.23.0) - opentelemetry-instrumentation-sidekiq (0.26.0) + opentelemetry-instrumentation-sidekiq (0.26.1) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.23.0) opentelemetry-registry (0.4.0) @@ -688,7 +688,7 @@ GEM link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.7.0) rdf (~> 3.3) - rdoc (6.12.0) + rdoc (6.13.1) psych (>= 4.0.0) redcarpet (3.6.1) redis (4.8.1) @@ -740,7 +740,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 9) rspec-support (3.13.2) - rubocop (1.75.1) + rubocop (1.75.2) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -748,10 +748,10 @@ GEM parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.43.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.43.0) + rubocop-ast (1.44.0) parser (>= 3.3.7.2) prism (~> 1.4) rubocop-capybara (2.22.1) @@ -840,7 +840,7 @@ GEM stoplight (4.1.1) redlock (~> 1.0) stringio (3.1.6) - strong_migrations (2.2.1) + strong_migrations (2.3.0) activerecord (>= 7) swd (2.0.3) activesupport (>= 3) @@ -851,7 +851,7 @@ GEM temple (0.10.3) terminal-table (4.0.0) unicode-display_width (>= 1.1.1, < 4) - terrapin (1.0.1) + terrapin (1.1.0) climate_control test-prof (1.4.4) thor (1.3.2) @@ -1085,4 +1085,4 @@ RUBY VERSION ruby 3.4.1p0 BUNDLED WITH - 2.6.6 + 2.6.7 diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index 5f7ef8dd63..ffe612f468 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -10,8 +10,6 @@ module SignatureVerification EXPIRATION_WINDOW_LIMIT = 12.hours CLOCK_SKEW_MARGIN = 1.hour - class SignatureVerificationError < StandardError; end - def require_account_signature! render json: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_account end @@ -34,7 +32,7 @@ module SignatureVerification def signature_key_id signature_params['keyId'] - rescue SignatureVerificationError + rescue Mastodon::SignatureVerificationError nil end @@ -45,17 +43,17 @@ module SignatureVerification def signed_request_actor return @signed_request_actor if defined?(@signed_request_actor) - raise SignatureVerificationError, 'Request not signed' unless signed_request? - raise SignatureVerificationError, 'Incompatible request signature. keyId and signature are required' if missing_required_signature_parameters? - raise SignatureVerificationError, 'Unsupported signature algorithm (only rsa-sha256 and hs2019 are supported)' unless %w(rsa-sha256 hs2019).include?(signature_algorithm) - raise SignatureVerificationError, 'Signed request date outside acceptable time window' unless matches_time_window? + raise Mastodon::SignatureVerificationError, 'Request not signed' unless signed_request? + raise Mastodon::SignatureVerificationError, 'Incompatible request signature. keyId and signature are required' if missing_required_signature_parameters? + raise Mastodon::SignatureVerificationError, 'Unsupported signature algorithm (only rsa-sha256 and hs2019 are supported)' unless %w(rsa-sha256 hs2019).include?(signature_algorithm) + raise Mastodon::SignatureVerificationError, 'Signed request date outside acceptable time window' unless matches_time_window? verify_signature_strength! verify_body_digest! actor = actor_from_key_id(signature_params['keyId']) - raise SignatureVerificationError, "Public key not found for key #{signature_params['keyId']}" if actor.nil? + raise Mastodon::SignatureVerificationError, "Public key not found for key #{signature_params['keyId']}" if actor.nil? signature = Base64.decode64(signature_params['signature']) compare_signed_string = build_signed_string(include_query_string: true) @@ -68,7 +66,7 @@ module SignatureVerification actor = stoplight_wrapper.run { actor_refresh_key!(actor) } - raise SignatureVerificationError, "Could not refresh public key #{signature_params['keyId']}" if actor.nil? + raise Mastodon::SignatureVerificationError, "Could not refresh public key #{signature_params['keyId']}" if actor.nil? compare_signed_string = build_signed_string(include_query_string: true) return actor unless verify_signature(actor, signature, compare_signed_string).nil? @@ -78,7 +76,7 @@ module SignatureVerification return actor unless verify_signature(actor, signature, compare_signed_string).nil? fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)", signed_string: compare_signed_string, signature: signature_params['signature'] - rescue SignatureVerificationError => e + rescue Mastodon::SignatureVerificationError => e fail_with! e.message rescue *Mastodon::HTTP_CONNECTION_ERRORS => e fail_with! "Failed to fetch remote data: #{e.message}" @@ -104,7 +102,7 @@ module SignatureVerification def signature_params @signature_params ||= SignatureParser.parse(request.headers['Signature']) rescue SignatureParser::ParsingError - raise SignatureVerificationError, 'Error parsing signature parameters' + raise Mastodon::SignatureVerificationError, 'Error parsing signature parameters' end def signature_algorithm @@ -116,31 +114,31 @@ module SignatureVerification end def verify_signature_strength! - raise SignatureVerificationError, 'Mastodon requires the Date header or (created) pseudo-header to be signed' unless signed_headers.include?('date') || signed_headers.include?('(created)') - raise SignatureVerificationError, 'Mastodon requires the Digest header or (request-target) pseudo-header to be signed' unless signed_headers.include?(HttpSignatureDraft::REQUEST_TARGET) || signed_headers.include?('digest') - raise SignatureVerificationError, 'Mastodon requires the Host header to be signed when doing a GET request' if request.get? && !signed_headers.include?('host') - raise SignatureVerificationError, 'Mastodon requires the Digest header to be signed when doing a POST request' if request.post? && !signed_headers.include?('digest') + raise Mastodon::SignatureVerificationError, 'Mastodon requires the Date header or (created) pseudo-header to be signed' unless signed_headers.include?('date') || signed_headers.include?('(created)') + raise Mastodon::SignatureVerificationError, 'Mastodon requires the Digest header or (request-target) pseudo-header to be signed' unless signed_headers.include?(HttpSignatureDraft::REQUEST_TARGET) || signed_headers.include?('digest') + raise Mastodon::SignatureVerificationError, 'Mastodon requires the Host header to be signed when doing a GET request' if request.get? && !signed_headers.include?('host') + raise Mastodon::SignatureVerificationError, 'Mastodon requires the Digest header to be signed when doing a POST request' if request.post? && !signed_headers.include?('digest') end def verify_body_digest! return unless signed_headers.include?('digest') - raise SignatureVerificationError, 'Digest header missing' unless request.headers.key?('Digest') + raise Mastodon::SignatureVerificationError, 'Digest header missing' unless request.headers.key?('Digest') digests = request.headers['Digest'].split(',').map { |digest| digest.split('=', 2) }.map { |key, value| [key.downcase, value] } sha256 = digests.assoc('sha-256') - raise SignatureVerificationError, "Mastodon only supports SHA-256 in Digest header. Offered algorithms: #{digests.map(&:first).join(', ')}" if sha256.nil? + raise Mastodon::SignatureVerificationError, "Mastodon only supports SHA-256 in Digest header. Offered algorithms: #{digests.map(&:first).join(', ')}" if sha256.nil? return if body_digest == sha256[1] digest_size = begin Base64.strict_decode64(sha256[1].strip).length rescue ArgumentError - raise SignatureVerificationError, "Invalid Digest value. The provided Digest value is not a valid base64 string. Given digest: #{sha256[1]}" + raise Mastodon::SignatureVerificationError, "Invalid Digest value. The provided Digest value is not a valid base64 string. Given digest: #{sha256[1]}" end - raise SignatureVerificationError, "Invalid Digest value. The provided Digest value is not a SHA-256 digest. Given digest: #{sha256[1]}" if digest_size != 32 + raise Mastodon::SignatureVerificationError, "Invalid Digest value. The provided Digest value is not a SHA-256 digest. Given digest: #{sha256[1]}" if digest_size != 32 - raise SignatureVerificationError, "Invalid Digest value. Computed SHA-256 digest: #{body_digest}; given: #{sha256[1]}" + raise Mastodon::SignatureVerificationError, "Invalid Digest value. Computed SHA-256 digest: #{body_digest}; given: #{sha256[1]}" end def verify_signature(actor, signature, compare_signed_string) @@ -165,13 +163,13 @@ module SignatureVerification "#{HttpSignatureDraft::REQUEST_TARGET}: #{request.method.downcase} #{request.path}" end when '(created)' - raise SignatureVerificationError, 'Invalid pseudo-header (created) for rsa-sha256' unless signature_algorithm == 'hs2019' - raise SignatureVerificationError, 'Pseudo-header (created) used but corresponding argument missing' if signature_params['created'].blank? + raise Mastodon::SignatureVerificationError, 'Invalid pseudo-header (created) for rsa-sha256' unless signature_algorithm == 'hs2019' + raise Mastodon::SignatureVerificationError, 'Pseudo-header (created) used but corresponding argument missing' if signature_params['created'].blank? "(created): #{signature_params['created']}" when '(expires)' - raise SignatureVerificationError, 'Invalid pseudo-header (expires) for rsa-sha256' unless signature_algorithm == 'hs2019' - raise SignatureVerificationError, 'Pseudo-header (expires) used but corresponding argument missing' if signature_params['expires'].blank? + raise Mastodon::SignatureVerificationError, 'Invalid pseudo-header (expires) for rsa-sha256' unless signature_algorithm == 'hs2019' + raise Mastodon::SignatureVerificationError, 'Pseudo-header (expires) used but corresponding argument missing' if signature_params['expires'].blank? "(expires): #{signature_params['expires']}" else @@ -193,7 +191,7 @@ module SignatureVerification expires_time = Time.at(signature_params['expires'].to_i).utc if signature_params['expires'].present? rescue ArgumentError => e - raise SignatureVerificationError, "Invalid Date header: #{e.message}" + raise Mastodon::SignatureVerificationError, "Invalid Date header: #{e.message}" end expires_time ||= created_time + 5.minutes unless created_time.nil? @@ -233,9 +231,9 @@ module SignatureVerification account end rescue Mastodon::PrivateNetworkAddressError => e - raise SignatureVerificationError, "Requests to private network addresses are disallowed (tried to query #{e.host})" + raise Mastodon::SignatureVerificationError, "Requests to private network addresses are disallowed (tried to query #{e.host})" rescue Mastodon::HostValidationError, ActivityPub::FetchRemoteActorService::Error, ActivityPub::FetchRemoteKeyService::Error, Webfinger::Error => e - raise SignatureVerificationError, e.message + raise Mastodon::SignatureVerificationError, e.message end def stoplight_wrapper @@ -251,8 +249,8 @@ module SignatureVerification ActivityPub::FetchRemoteActorService.new.call(actor.uri, only_key: true, suppress_errors: false) rescue Mastodon::PrivateNetworkAddressError => e - raise SignatureVerificationError, "Requests to private network addresses are disallowed (tried to query #{e.host})" + raise Mastodon::SignatureVerificationError, "Requests to private network addresses are disallowed (tried to query #{e.host})" rescue Mastodon::HostValidationError, ActivityPub::FetchRemoteActorService::Error, Webfinger::Error => e - raise SignatureVerificationError, e.message + raise Mastodon::SignatureVerificationError, e.message end end diff --git a/app/javascript/mastodon/actions/domain_blocks.js b/app/javascript/mastodon/actions/domain_blocks.js index 727f800af3..279ec1bef7 100644 --- a/app/javascript/mastodon/actions/domain_blocks.js +++ b/app/javascript/mastodon/actions/domain_blocks.js @@ -12,14 +12,6 @@ export const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL'; export const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST'; export const DOMAIN_UNBLOCK_FAIL = 'DOMAIN_UNBLOCK_FAIL'; -export const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST'; -export const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS'; -export const DOMAIN_BLOCKS_FETCH_FAIL = 'DOMAIN_BLOCKS_FETCH_FAIL'; - -export const DOMAIN_BLOCKS_EXPAND_REQUEST = 'DOMAIN_BLOCKS_EXPAND_REQUEST'; -export const DOMAIN_BLOCKS_EXPAND_SUCCESS = 'DOMAIN_BLOCKS_EXPAND_SUCCESS'; -export const DOMAIN_BLOCKS_EXPAND_FAIL = 'DOMAIN_BLOCKS_EXPAND_FAIL'; - export function blockDomain(domain) { return (dispatch, getState) => { dispatch(blockDomainRequest(domain)); @@ -79,80 +71,6 @@ export function unblockDomainFail(domain, error) { }; } -export function fetchDomainBlocks() { - return (dispatch) => { - dispatch(fetchDomainBlocksRequest()); - - api().get('/api/v1/domain_blocks').then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null)); - }).catch(err => { - dispatch(fetchDomainBlocksFail(err)); - }); - }; -} - -export function fetchDomainBlocksRequest() { - return { - type: DOMAIN_BLOCKS_FETCH_REQUEST, - }; -} - -export function fetchDomainBlocksSuccess(domains, next) { - return { - type: DOMAIN_BLOCKS_FETCH_SUCCESS, - domains, - next, - }; -} - -export function fetchDomainBlocksFail(error) { - return { - type: DOMAIN_BLOCKS_FETCH_FAIL, - error, - }; -} - -export function expandDomainBlocks() { - return (dispatch, getState) => { - const url = getState().getIn(['domain_lists', 'blocks', 'next']); - - if (!url) { - return; - } - - dispatch(expandDomainBlocksRequest()); - - api().get(url).then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null)); - }).catch(err => { - dispatch(expandDomainBlocksFail(err)); - }); - }; -} - -export function expandDomainBlocksRequest() { - return { - type: DOMAIN_BLOCKS_EXPAND_REQUEST, - }; -} - -export function expandDomainBlocksSuccess(domains, next) { - return { - type: DOMAIN_BLOCKS_EXPAND_SUCCESS, - domains, - next, - }; -} - -export function expandDomainBlocksFail(error) { - return { - type: DOMAIN_BLOCKS_EXPAND_FAIL, - error, - }; -} - export const initDomainBlockModal = account => dispatch => dispatch(openModal({ modalType: 'DOMAIN_BLOCK', modalProps: { diff --git a/app/javascript/mastodon/api/domain_blocks.ts b/app/javascript/mastodon/api/domain_blocks.ts new file mode 100644 index 0000000000..4e153b0ee9 --- /dev/null +++ b/app/javascript/mastodon/api/domain_blocks.ts @@ -0,0 +1,13 @@ +import api, { getLinks } from 'mastodon/api'; + +export const apiGetDomainBlocks = async (url?: string) => { + const response = await api().request({ + method: 'GET', + url: url ?? '/api/v1/domain_blocks', + }); + + return { + domains: response.data, + links: getLinks(response), + }; +}; diff --git a/app/javascript/mastodon/components/copy_icon_button.jsx b/app/javascript/mastodon/components/copy_icon_button.tsx similarity index 62% rename from app/javascript/mastodon/components/copy_icon_button.jsx rename to app/javascript/mastodon/components/copy_icon_button.tsx index 0c3c6c290b..29f5f34430 100644 --- a/app/javascript/mastodon/components/copy_icon_button.jsx +++ b/app/javascript/mastodon/components/copy_icon_button.tsx @@ -1,29 +1,36 @@ -import PropTypes from 'prop-types'; import { useState, useCallback } from 'react'; import { defineMessages } from 'react-intl'; import classNames from 'classnames'; -import { useDispatch } from 'react-redux'; - import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; import { showAlert } from 'mastodon/actions/alerts'; import { IconButton } from 'mastodon/components/icon_button'; +import { useAppDispatch } from 'mastodon/store'; const messages = defineMessages({ - copied: { id: 'copy_icon_button.copied', defaultMessage: 'Copied to clipboard' }, + copied: { + id: 'copy_icon_button.copied', + defaultMessage: 'Copied to clipboard', + }, }); -export const CopyIconButton = ({ title, value, className }) => { +export const CopyIconButton: React.FC<{ + title: string; + value: string; + className: string; +}> = ({ title, value, className }) => { const [copied, setCopied] = useState(false); - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); const handleClick = useCallback(() => { - navigator.clipboard.writeText(value); + void navigator.clipboard.writeText(value); setCopied(true); dispatch(showAlert({ message: messages.copied })); - setTimeout(() => setCopied(false), 700); + setTimeout(() => { + setCopied(false); + }, 700); }, [setCopied, value, dispatch]); return ( @@ -31,13 +38,8 @@ export const CopyIconButton = ({ title, value, className }) => { className={classNames(className, copied ? 'copied' : 'copyable')} title={title} onClick={handleClick} + icon='' iconComponent={ContentCopyIcon} /> ); }; - -CopyIconButton.propTypes = { - title: PropTypes.string, - value: PropTypes.string, - className: PropTypes.string, -}; diff --git a/app/javascript/mastodon/components/domain.tsx b/app/javascript/mastodon/components/domain.tsx index aa64f0f8c3..0ccffac482 100644 --- a/app/javascript/mastodon/components/domain.tsx +++ b/app/javascript/mastodon/components/domain.tsx @@ -1,24 +1,15 @@ import { useCallback } from 'react'; -import { defineMessages, useIntl } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; -import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react'; import { unblockDomain } from 'mastodon/actions/domain_blocks'; import { useAppDispatch } from 'mastodon/store'; -import { IconButton } from './icon_button'; - -const messages = defineMessages({ - unblockDomain: { - id: 'account.unblock_domain', - defaultMessage: 'Unblock domain {domain}', - }, -}); +import { Button } from './button'; export const Domain: React.FC<{ domain: string; }> = ({ domain }) => { - const intl = useIntl(); const dispatch = useAppDispatch(); const handleDomainUnblock = useCallback(() => { @@ -27,20 +18,17 @@ export const Domain: React.FC<{ return (
-
- - {domain} - +
+ {domain} +
-
- +
+
); diff --git a/app/javascript/mastodon/features/domain_blocks/index.jsx b/app/javascript/mastodon/features/domain_blocks/index.jsx deleted file mode 100644 index 3656596806..0000000000 --- a/app/javascript/mastodon/features/domain_blocks/index.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import PropTypes from 'prop-types'; - -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -import { Helmet } from 'react-helmet'; - -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; - -import { debounce } from 'lodash'; - -import BlockIcon from '@/material-icons/400-24px/block-fill.svg?react'; -import { Domain } from 'mastodon/components/domain'; - -import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks'; -import { LoadingIndicator } from '../../components/loading_indicator'; -import ScrollableList from '../../components/scrollable_list'; -import Column from '../ui/components/column'; - -const messages = defineMessages({ - heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' }, -}); - -const mapStateToProps = state => ({ - domains: state.getIn(['domain_lists', 'blocks', 'items']), - hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']), -}); - -class Blocks extends ImmutablePureComponent { - - static propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - hasMore: PropTypes.bool, - domains: ImmutablePropTypes.orderedSet, - intl: PropTypes.object.isRequired, - multiColumn: PropTypes.bool, - }; - - UNSAFE_componentWillMount () { - this.props.dispatch(fetchDomainBlocks()); - } - - handleLoadMore = debounce(() => { - this.props.dispatch(expandDomainBlocks()); - }, 300, { leading: true }); - - render () { - const { intl, domains, hasMore, multiColumn } = this.props; - - if (!domains) { - return ( - - - - ); - } - - const emptyMessage = ; - - return ( - - - {domains.map(domain => - , - )} - - - - - - - ); - } - -} - -export default connect(mapStateToProps)(injectIntl(Blocks)); diff --git a/app/javascript/mastodon/features/domain_blocks/index.tsx b/app/javascript/mastodon/features/domain_blocks/index.tsx new file mode 100644 index 0000000000..900aba4745 --- /dev/null +++ b/app/javascript/mastodon/features/domain_blocks/index.tsx @@ -0,0 +1,113 @@ +import { useEffect, useRef, useCallback, useState } from 'react'; + +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; + +import { Helmet } from 'react-helmet'; + +import BlockIcon from '@/material-icons/400-24px/block-fill.svg?react'; +import { apiGetDomainBlocks } from 'mastodon/api/domain_blocks'; +import { Column } from 'mastodon/components/column'; +import type { ColumnRef } from 'mastodon/components/column'; +import { ColumnHeader } from 'mastodon/components/column_header'; +import { Domain } from 'mastodon/components/domain'; +import ScrollableList from 'mastodon/components/scrollable_list'; + +const messages = defineMessages({ + heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' }, +}); + +const Blocks: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => { + const intl = useIntl(); + const [domains, setDomains] = useState([]); + const [loading, setLoading] = useState(false); + const [next, setNext] = useState(); + const hasMore = !!next; + const columnRef = useRef(null); + + useEffect(() => { + setLoading(true); + + void apiGetDomainBlocks() + .then(({ domains, links }) => { + const next = links.refs.find((link) => link.rel === 'next'); + + setLoading(false); + setDomains(domains); + setNext(next?.uri); + + return ''; + }) + .catch(() => { + setLoading(false); + }); + }, [setLoading, setDomains, setNext]); + + const handleLoadMore = useCallback(() => { + setLoading(true); + + void apiGetDomainBlocks(next) + .then(({ domains, links }) => { + const next = links.refs.find((link) => link.rel === 'next'); + + setLoading(false); + setDomains((previousDomains) => [...previousDomains, ...domains]); + setNext(next?.uri); + + return ''; + }) + .catch(() => { + setLoading(false); + }); + }, [setLoading, setDomains, setNext, next]); + + const handleHeaderClick = useCallback(() => { + columnRef.current?.scrollTop(); + }, []); + + const emptyMessage = ( + + ); + + return ( + + + + + {domains.map((domain) => ( + + ))} + + + + {intl.formatMessage(messages.heading)} + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default Blocks; diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index cdf79c8edc..a282796a50 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicació} other {{counter} publicacions}}", "account.unblock": "Desbloca @{name}", "account.unblock_domain": "Desbloca el domini {domain}", + "account.unblock_domain_short": "Desbloca", "account.unblock_short": "Desbloca", "account.unendorse": "No recomanis en el perfil", "account.unfollow": "Deixa de seguir", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index deced039c2..4ffef4f392 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} příspěvek} few {{counter} příspěvky} many {{counter} příspěvků} other {{counter} příspěvků}}", "account.unblock": "Odblokovat @{name}", "account.unblock_domain": "Odblokovat doménu {domain}", + "account.unblock_domain_short": "Odblokovat", "account.unblock_short": "Odblokovat", "account.unendorse": "Nezvýrazňovat na profilu", "account.unfollow": "Přestat sledovat", @@ -79,7 +80,7 @@ "admin.dashboard.retention.cohort_size": "Noví uživatelé", "admin.impact_report.instance_accounts": "Profily účtů, které by byli odstaněny", "admin.impact_report.instance_followers": "Sledující, o které by naši uživatelé přišli", - "admin.impact_report.instance_follows": "Sledující, o které by naši uživatelé přišli", + "admin.impact_report.instance_follows": "Sledující, o které by jejich uživatelé přišli", "admin.impact_report.title": "Shrnutí dopadu", "alert.rate_limited.message": "Zkuste to prosím znovu po {retry_time, time, medium}.", "alert.rate_limited.title": "Spojení omezena", @@ -101,7 +102,7 @@ "annual_report.summary.archetype.replier": "Sociální motýlek", "annual_report.summary.followers.followers": "sledujících", "annual_report.summary.followers.total": "{count} celkem", - "annual_report.summary.here_it_is": "Zde je tvůj {year} v přehledu:", + "annual_report.summary.here_it_is": "Zde je tvůj rok {year} v přehledu:", "annual_report.summary.highlighted_post.by_favourites": "nejvíce oblíbený příspěvek", "annual_report.summary.highlighted_post.by_reblogs": "nejvíce boostovaný příspěvek", "annual_report.summary.highlighted_post.by_replies": "příspěvek s nejvíce odpověďmi", @@ -267,7 +268,7 @@ "domain_pill.activitypub_like_language": "ActivityPub je jako jazyk, kterým Mastodon mluví s jinými sociálními sítěmi.", "domain_pill.server": "Server", "domain_pill.their_handle": "Handle:", - "domain_pill.their_server": "Jejich digitální domov, kde žijí jejich všechny příspěvky.", + "domain_pill.their_server": "Jejich digitální domov, kde žijí všechny jejich příspěvky.", "domain_pill.their_username": "Jejich jedinečný identifikátor na jejich serveru. Je možné, že na jiných serverech jsou uživatelé se stejným uživatelským jménem.", "domain_pill.username": "Uživatelské jméno", "domain_pill.whats_in_a_handle": "Co obsahuje handle?", @@ -572,7 +573,7 @@ "notification.label.private_reply": "Privátní odpověď", "notification.label.reply": "Odpověď", "notification.mention": "Zmínka", - "notification.mentioned_you": "{name} vás zmínil", + "notification.mentioned_you": "{name} vás zmínil*a", "notification.moderation-warning.learn_more": "Zjistit více", "notification.moderation_warning": "Obdrželi jste varování od moderátorů", "notification.moderation_warning.action_delete_statuses": "Některé z vašich příspěvků byly odstraněny.", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index c107cbebe3..27ecc6e8eb 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} postiad} two {{counter} bostiad} few {{counter} phostiad} many {{counter} postiad} other {{counter} postiad}}", "account.unblock": "Dadrwystro @{name}", "account.unblock_domain": "Dadrwystro parth {domain}", + "account.unblock_domain_short": "Dadrwystro", "account.unblock_short": "Dadrwystro", "account.unendorse": "Peidio a'i ddangos ar fy mhroffil", "account.unfollow": "Dad-ddilyn", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index c5d7fc66f5..d8695c194c 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} indlæg} other {{counter} indlæg}}", "account.unblock": "Fjern blokering af @{name}", "account.unblock_domain": "Fjern blokering af domænet {domain}", + "account.unblock_domain_short": "Afblokér", "account.unblock_short": "Fjern blokering", "account.unendorse": "Fjern visning på din profil", "account.unfollow": "Følg ikke længere", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index debb2db480..6a14858d11 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} Beitrag} other {{counter} Beiträge}}", "account.unblock": "{name} nicht mehr blockieren", "account.unblock_domain": "Blockierung von {domain} aufheben", + "account.unblock_domain_short": "Entsperren", "account.unblock_short": "Blockierung aufheben", "account.unendorse": "Im Profil nicht mehr empfehlen", "account.unfollow": "Entfolgen", diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 424983840e..ebd5412cf2 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} posts}}", "account.unblock": "Unblock @{name}", "account.unblock_domain": "Unblock domain {domain}", + "account.unblock_domain_short": "Unblock", "account.unblock_short": "Unblock", "account.unendorse": "Don't feature on profile", "account.unfollow": "Unfollow", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 724fd5d274..2eb96dd5bd 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} mensaje} other {{counter} mensajes}}", "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Desbloquear dominio {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "No destacar en el perfil", "account.unfollow": "Dejar de seguir", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 0fe0f1cad3..dbaf1955e4 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicaciones}}", "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Mostrar a {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "No mostrar en el perfil", "account.unfollow": "Dejar de seguir", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 8d6bb4cdbe..be6a0f95ee 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicaciones}}", "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Desbloquear dominio {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "No mostrar en el perfil", "account.unfollow": "Dejar de seguir", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 3e5a327301..4be3211045 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} julkaisu} other {{counter} julkaisua}}", "account.unblock": "Kumoa käyttäjän @{name} esto", "account.unblock_domain": "Kumoa verkkotunnuksen {domain} esto", + "account.unblock_domain_short": "Kumoa esto", "account.unblock_short": "Kumoa esto", "account.unendorse": "Kumoa suosittelu profiilissasi", "account.unfollow": "Älä seuraa", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 06ab07023e..636d32729c 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} postur} other {{counter} postar}}", "account.unblock": "Banna ikki @{name}", "account.unblock_domain": "Banna ikki økisnavnið {domain}", + "account.unblock_domain_short": "Banna ikki", "account.unblock_short": "Banna ikki", "account.unendorse": "Vís ikki á vanga", "account.unfollow": "Fylg ikki", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 8106c86714..6eb5457043 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicacións}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Amosar {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "Non amosar no perfil", "account.unfollow": "Deixar de seguir", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index f31b862a03..f5c6e66f9b 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -64,8 +64,9 @@ "account.show_reblogs": "הצג הדהודים מאת @{name}", "account.statuses_counter": "{count, plural, one {הודעה אחת} two {הודעותיים} many {{counter} הודעות} other {{counter} הודעות}}", "account.unblock": "להסיר חסימה ל- @{name}", - "account.unblock_domain": "הסירי את החסימה של קהילת {domain}", - "account.unblock_short": "הסר חסימה", + "account.unblock_domain": "הסרת החסימה של קהילת {domain}", + "account.unblock_domain_short": "הסרת חסימה", + "account.unblock_short": "הסרת חסימה", "account.unendorse": "אל תקדם בפרופיל", "account.unfollow": "הפסקת מעקב", "account.unmute": "הפסקת השתקת @{name}", @@ -905,6 +906,12 @@ "video.expand": "להרחיב וידאו", "video.fullscreen": "מסך מלא", "video.hide": "להסתיר וידאו", + "video.mute": "השתקה", "video.pause": "השהיה", - "video.play": "ניגון" + "video.play": "ניגון", + "video.skip_backward": "דילוג אחורה", + "video.skip_forward": "דילוג קדימה", + "video.unmute": "ביטול השתקה", + "video.volume_down": "הנמכת עוצמת השמע", + "video.volume_up": "הגברת עוצמת שמע" } diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 942c96ffec..2caba889e3 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} bejegyzés} other {{counter} bejegyzés}}", "account.unblock": "@{name} letiltásának feloldása", "account.unblock_domain": "{domain} domain tiltásának feloldása", + "account.unblock_domain_short": "Tiltás feloldása", "account.unblock_short": "Tiltás feloldása", "account.unendorse": "Ne jelenjen meg a profilodon", "account.unfollow": "Követés megszüntetése", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 47cd31fd6b..db257927fc 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} færsla} other {{counter} færslur}}", "account.unblock": "Aflétta útilokun af @{name}", "account.unblock_domain": "Aflétta útilokun lénsins {domain}", + "account.unblock_domain_short": "Aflétta útilokun", "account.unblock_short": "Hætta að loka á", "account.unendorse": "Ekki birta á notandasniði", "account.unfollow": "Hætta að fylgja", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index e80182031e..9fa5c725b6 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -70,7 +70,7 @@ "account.unfollow": "Smetti di seguire", "account.unmute": "Riattiva @{name}", "account.unmute_notifications_short": "Riattiva notifiche", - "account.unmute_short": "Riattiva", + "account.unmute_short": "Attiva audio", "account_note.placeholder": "Clicca per aggiungere una nota", "admin.dashboard.daily_retention": "Tasso di ritenzione dell'utente per giorno, dopo la registrazione", "admin.dashboard.monthly_retention": "Tasso di ritenzione dell'utente per mese, dopo la registrazione", @@ -905,6 +905,12 @@ "video.expand": "Espandi il video", "video.fullscreen": "Schermo intero", "video.hide": "Nascondi il video", + "video.mute": "Muta", "video.pause": "Pausa", - "video.play": "Riproduci" + "video.play": "Riproduci", + "video.skip_backward": "Vai indietro", + "video.skip_forward": "Vai avanti", + "video.unmute": "Muta", + "video.volume_down": "Abbassa volume", + "video.volume_up": "Alza volume" } diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 881a543681..c4d9d75c0e 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -61,6 +61,7 @@ "account.statuses_counter": "{count, plural, one {{counter} n tsuffeɣt} other {{counter} n tsuffaɣ}}", "account.unblock": "Serreḥ i @{name}", "account.unblock_domain": "Ssken-d {domain}", + "account.unblock_domain_short": "Serreḥ", "account.unblock_short": "Serreḥ", "account.unendorse": "Ur ttwellih ara fell-as deg umaɣnu-inek", "account.unfollow": "Ur ṭṭafaṛ ara", @@ -77,6 +78,7 @@ "alt_text_modal.cancel": "Semmet", "alt_text_modal.done": "Immed", "announcement.announcement": "Ulɣu", + "annual_report.summary.most_used_app.most_used_app": "asnas yettwasqedcen s waṭas", "annual_report.summary.most_used_hashtag.none": "Ula yiwen", "annual_report.summary.new_posts.new_posts": "tisuffaɣ timaynutin", "audio.hide": "Ffer amesli", @@ -162,6 +164,7 @@ "confirmations.discard_edit_media.confirm": "Sefsex", "confirmations.edit.confirm": "Ẓreg", "confirmations.edit.message": "Abeddel tura ad d-yaru izen-nni i d-tegreḍ akka tura. Tetḥeqqeḍ tebɣiḍ ad tkemmleḍ?", + "confirmations.follow_to_list.confirm": "Ḍfeṛ-it sakin rnu-t ɣer tebdart", "confirmations.logout.confirm": "Ffeɣ", "confirmations.logout.message": "D tidet tebɣiḍ ad teffɣeḍ?", "confirmations.logout.title": "Tebɣiḍ ad teffɣeḍ ssya?", @@ -245,6 +248,7 @@ "filter_modal.select_filter.search": "Nadi neɣ snulfu-d", "filter_modal.select_filter.title": "Sizdeg tassufeɣt-a", "filter_modal.title.status": "Sizdeg tassufeɣt", + "filtered_notifications_banner.title": "Ilɣa yettwasizdgen", "firehose.all": "Akk", "firehose.local": "Deg uqeddac-ayi", "firehose.remote": "Iqeddacen nniḍen", @@ -350,9 +354,12 @@ "lists.add_to_lists": "Rnu {name} ɣer tebdarin", "lists.create": "Snulfu-d", "lists.delete": "Kkes tabdart", + "lists.done": "Immed", "lists.edit": "Ẓreg tabdart", "lists.list_name": "Isem n tebdart", "lists.new_list_name": "Isem n tebdart tamaynut", + "lists.no_lists_yet": "Ulac tibdarin akka tura.", + "lists.no_results_found": "Ulac igemmad.", "lists.remove_member": "Kkes", "lists.replies_policy.followed": "Kra n useqdac i yettwaḍefren", "lists.replies_policy.list": "Iɛeggalen n tebdart", @@ -389,6 +396,7 @@ "navigation_bar.follows_and_followers": "Imeḍfaṛen akked wid i teṭṭafaṛeḍ", "navigation_bar.lists": "Tibdarin", "navigation_bar.logout": "Ffeɣ", + "navigation_bar.moderation": "Aseɣyed", "navigation_bar.mutes": "Iseqdacen yettwasusmen", "navigation_bar.opened_in_classic_interface": "Tisuffaɣ, imiḍanen akked isebtar-nniḍen igejdanen ldin-d s wudem amezwer deg ugrudem web aklasiki.", "navigation_bar.personal": "Udmawan", @@ -419,6 +427,7 @@ "notification_requests.edit_selection": "Ẓreg", "notification_requests.exit_selection": "Immed", "notification_requests.notifications_from": "Alɣuten sɣur {name}", + "notification_requests.title": "Ilɣa yettwasizdgen", "notifications.clear": "Sfeḍ alɣuten", "notifications.clear_confirmation": "Tebɣiḍ s tidet ad tekkseḍ akk alɣuten-inek·em i lebda?", "notifications.column_settings.admin.report": "Ineqqisen imaynuten:", @@ -463,6 +472,7 @@ "onboarding.follows.back": "Uɣal", "onboarding.follows.done": "Immed", "onboarding.follows.search": "Nadi", + "onboarding.follows.title": "Ḍfeṛ walbɛaḍ i wakken ad ttebdud", "onboarding.profile.display_name": "Isem ara d-yettwaskanen", "onboarding.profile.display_name_hint": "Isem-ik·im ummid neɣ isem-ik·im n uqeṣṣer…", "onboarding.profile.note": "Tameddurt", @@ -484,15 +494,18 @@ "poll_button.remove_poll": "Kkes asenqed", "privacy.change": "Seggem tabaḍnit n yizen", "privacy.direct.long": "Wid akk i d-yettwabdaren deg tsuffeɣt", + "privacy.direct.short": "Abdar uslig", "privacy.private.long": "Ala wid i k·m-yeṭṭafaṛen", "privacy.private.short": "Imeḍfaren", "privacy.public.long": "Kra n win yellan deg Masṭudun neɣ berra-s", "privacy.public.short": "Azayez", "privacy.unlisted.long": "Kra kan yiwarzimen", + "privacy.unlisted.short": "Azayez asusam", "privacy_policy.last_updated": "Aleqqem aneggaru {date}", "privacy_policy.title": "Tasertit tabaḍnit", "recommended": "Yettuwelleh", "refresh": "Smiren", + "regeneration_indicator.please_stand_by": "Ttxil rǧu.", "relative_time.days": "{number}u", "relative_time.full.just_now": "tura kan", "relative_time.hours": "{number}isr", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index c1aef7ff7d..a4af036527 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} bericht} other {{counter} berichten}}", "account.unblock": "@{name} deblokkeren", "account.unblock_domain": "{domain} niet langer blokkeren", + "account.unblock_domain_short": "Deblokkeren", "account.unblock_short": "Deblokkeren", "account.unendorse": "Niet op profiel weergeven", "account.unfollow": "Ontvolgen", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index d5df6e59cf..32af518415 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} publicação} other {{counter} publicações}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Desbloquear o domínio {domain}", + "account.unblock_domain_short": "Desbloquear", "account.unblock_short": "Desbloquear", "account.unendorse": "Não destacar no perfil", "account.unfollow": "Deixar de seguir", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 116b3906a2..a80b3df80d 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} postim} other {{counter} postime}}", "account.unblock": "Zhbllokoje @{name}", "account.unblock_domain": "Zhblloko përkatësinë {domain}", + "account.unblock_domain_short": "Zhbllokoje", "account.unblock_short": "Zhbllokoje", "account.unendorse": "Mos e përfshi në profil", "account.unfollow": "Resht së ndjekuri", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 25fa1471b0..a33317ac9c 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} gönderi} other {{counter} gönderi}}", "account.unblock": "@{name} adlı kişinin engelini kaldır", "account.unblock_domain": "{domain} alan adının engelini kaldır", + "account.unblock_domain_short": "Engeli kaldır", "account.unblock_short": "Engeli kaldır", "account.unendorse": "Profilimde öne çıkarma", "account.unfollow": "Takibi bırak", @@ -905,6 +906,12 @@ "video.expand": "Videoyu genişlet", "video.fullscreen": "Tam ekran", "video.hide": "Videoyu gizle", + "video.mute": "Sessiz", "video.pause": "Duraklat", - "video.play": "Oynat" + "video.play": "Oynat", + "video.skip_backward": "Geriye atla", + "video.skip_forward": "İleriye atla", + "video.unmute": "Sesi aç", + "video.volume_down": "Sesi kıs", + "video.volume_up": "Sesi yükselt" } diff --git a/app/javascript/mastodon/locales/ug.json b/app/javascript/mastodon/locales/ug.json index 378f688ba8..e550d7e678 100644 --- a/app/javascript/mastodon/locales/ug.json +++ b/app/javascript/mastodon/locales/ug.json @@ -1,21 +1,34 @@ { - "about.blocks": "ئوتتۇراھال مۇلازىمېتىر", - "about.contact": "ئالاقىلاشقۇچى:", - "account.badges.bot": "Bot", - "account.cancel_follow_request": "Withdraw follow request", - "account.posts": "Toots", - "account.posts_with_replies": "Toots and replies", + "about.blocks": "باشقۇرۇلىدىغان مۇلازىمېتىر", + "about.contact": "ئالاقە:", + "about.disclaimer": "Mastodon ھەقسىز، ئوچۇق كودلۇق يۇمشاق دېتال تاۋار ماركىسى Mastodon gGmbH غا تەۋە.", + "about.domain_blocks.no_reason_available": "سەۋەبىنى ئىشلەتكىلى بولمايدۇ", + "account.badges.bot": "ماشىنا ئادەم", + "account.cancel_follow_request": "ئەگىشىش ئىلتىماسىدىن ۋاز كەچ", + "account.posts": "يازما", + "account.posts_with_replies": "يازما ۋە ئىنكاس", + "account.report": "@{name} نى پاش قىل", "account.requested": "Awaiting approval", - "account_note.placeholder": "Click to add a note", - "column.pins": "Pinned toot", - "community.column_settings.media_only": "Media only", + "account_note.placeholder": "چېكىلسە ئىزاھات قوشىدۇ", + "column.pins": "چوققىلانغان يازما", + "community.column_settings.media_only": "ۋاسىتەلا", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", "compose_form.placeholder": "What is on your mind?", - "compose_form.publish_form": "Publish", - "compose_form.spoiler.marked": "Text is hidden behind warning", + "compose_form.publish_form": "يېڭى يازما", + "compose_form.reply": "جاۋاب", + "compose_form.save_changes": "يېڭىلا", + "compose_form.spoiler.marked": "مەزمۇن ئاگاھلاندۇرۇشىنى چىقىرىۋەت", "compose_form.spoiler.unmarked": "Text is not hidden", - "confirmations.delete.message": "Are you sure you want to delete this status?", + "compose_form.spoiler_placeholder": "مەزمۇن ئاگاھلاندۇرۇشى (تاللاشچان)", + "confirmation_modal.cancel": "ۋاز كەچ", + "confirmations.block.confirm": "توس", + "confirmations.delete.message": "بۇ يازمىنى راستىنلا ئۆچۈرەمسىز؟", + "confirmations.delete.title": "يازما ئۆچۈرەمدۇ؟", + "confirmations.delete_list.confirm": "ئۆچۈر", + "confirmations.delete_list.message": "بۇ تىزىمنى راستتىنلا مەڭگۈلۈك ئۆچۈرەمسىز؟", + "confirmations.delete_list.title": "تىزىمنى ئۆچۈرەمدۇ؟", + "confirmations.discard_edit_media.confirm": "تاشلىۋەت", "embed.instructions": "Embed this status on your website by copying the code below.", "empty_column.account_timeline": "No toots here!", "empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 85b0125c07..eb7931f02c 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, one {{counter} допис} few {{counter} дописи} many {{counter} дописів} other {{counter} допис}}", "account.unblock": "Розблокувати @{name}", "account.unblock_domain": "Розблокувати {domain}", + "account.unblock_domain_short": "Розблокувати", "account.unblock_short": "Розблокувати", "account.unendorse": "Не публікувати у профілі", "account.unfollow": "Відписатися", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index b179f50fa9..21a7e5da47 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, other {{counter} Tút}}", "account.unblock": "Bỏ chặn @{name}", "account.unblock_domain": "Bỏ ẩn {domain}", + "account.unblock_domain_short": "Bỏ chặn", "account.unblock_short": "Bỏ chặn", "account.unendorse": "Ngưng tôn vinh người này", "account.unfollow": "Bỏ theo dõi", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 710814f12d..f2b8665e49 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -65,6 +65,7 @@ "account.statuses_counter": "{count, plural, other {{count} 則嘟文}}", "account.unblock": "解除封鎖 @{name}", "account.unblock_domain": "解除封鎖網域 {domain}", + "account.unblock_domain_short": "解除封鎖", "account.unblock_short": "解除封鎖", "account.unendorse": "取消於個人檔案推薦對方", "account.unfollow": "取消跟隨", diff --git a/app/javascript/mastodon/reducers/domain_lists.js b/app/javascript/mastodon/reducers/domain_lists.js deleted file mode 100644 index 5f63c77f5d..0000000000 --- a/app/javascript/mastodon/reducers/domain_lists.js +++ /dev/null @@ -1,26 +0,0 @@ -import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable'; - -import { - DOMAIN_BLOCKS_FETCH_SUCCESS, - DOMAIN_BLOCKS_EXPAND_SUCCESS, - unblockDomainSuccess -} from '../actions/domain_blocks'; - -const initialState = ImmutableMap({ - blocks: ImmutableMap({ - items: ImmutableOrderedSet(), - }), -}); - -export default function domainLists(state = initialState, action) { - switch(action.type) { - case DOMAIN_BLOCKS_FETCH_SUCCESS: - return state.setIn(['blocks', 'items'], ImmutableOrderedSet(action.domains)).setIn(['blocks', 'next'], action.next); - case DOMAIN_BLOCKS_EXPAND_SUCCESS: - return state.updateIn(['blocks', 'items'], set => set.union(action.domains)).setIn(['blocks', 'next'], action.next); - case unblockDomainSuccess.type: - return state.updateIn(['blocks', 'items'], set => set.delete(action.payload.domain)); - default: - return state; - } -} diff --git a/app/javascript/mastodon/reducers/index.ts b/app/javascript/mastodon/reducers/index.ts index 08ec2e58a4..cd5f55a868 100644 --- a/app/javascript/mastodon/reducers/index.ts +++ b/app/javascript/mastodon/reducers/index.ts @@ -11,7 +11,6 @@ import { composeReducer } from './compose'; import contexts from './contexts'; import conversations from './conversations'; import custom_emojis from './custom_emojis'; -import domain_lists from './domain_lists'; import { dropdownMenuReducer } from './dropdown_menu'; import filters from './filters'; import followed_tags from './followed_tags'; @@ -49,7 +48,6 @@ const reducers = { loadingBar: loadingBarReducer, modal: modalReducer, user_lists, - domain_lists, status_lists, accounts: accountsReducer, accounts_map, diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index d6acd1e924..5f5202592a 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1882,29 +1882,21 @@ body > [data-popper-placement] { } .domain { - padding: 10px; + padding: 16px; border-bottom: 1px solid var(--background-border-color); + display: flex; + align-items: center; + gap: 8px; - .domain__domain-name { + &__domain-name { flex: 1 1 auto; - display: block; color: $primary-text-color; - text-decoration: none; - font-size: 14px; + font-size: 15px; + line-height: 21px; font-weight: 500; } } -.domain__wrapper { - display: flex; -} - -.domain_buttons { - height: 18px; - padding: 10px; - white-space: nowrap; -} - .account { padding: 16px; border-bottom: 1px solid var(--background-border-color); diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 29411774a1..0c98651d12 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -130,12 +130,7 @@ class ActivityPub::Activity def first_mentioned_local_account audience = (as_array(@json['to']) + as_array(@json['cc'])).map { |x| value_or_id(x) }.uniq - local_usernames = audience.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) } - .map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) } - - return if local_usernames.empty? - - Account.local.where(username: local_usernames).first + ActivityPub::TagManager.instance.uris_to_local_accounts(audience).first end def first_local_follower diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 64e45cb67a..0b4eadf231 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -412,11 +412,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def addresses_local_accounts? return true if @options[:delivered_to_account_id] - local_usernames = (audience_to + audience_cc).uniq.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) }.map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) } - - return false if local_usernames.empty? - - Account.local.exists?(username: local_usernames) + ActivityPub::TagManager.instance.uris_to_local_accounts((audience_to + audience_cc).uniq).exists? end def tombstone_exists? diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb index 5cba9a8006..2fe707e79b 100644 --- a/app/lib/activitypub/tag_manager.rb +++ b/app/lib/activitypub/tag_manager.rb @@ -203,6 +203,19 @@ class ActivityPub::TagManager path_params[param] end + def uris_to_local_accounts(uris) + usernames = [] + ids = [] + + uris.each do |uri| + param, value = uri_to_local_account_params(uri) + usernames << value.downcase if param == :username + ids << value if param == :id + end + + Account.local.with_username(usernames).or(Account.local.where(id: ids)) + end + def uri_to_actor(uri) uri_to_resource(uri, Account) end @@ -213,7 +226,7 @@ class ActivityPub::TagManager if local_uri?(uri) case klass.name when 'Account' - klass.find_local(uri_to_local_id(uri, :username)) + uris_to_local_accounts([uri]).first else StatusFinder.new(uri).status end @@ -225,4 +238,20 @@ class ActivityPub::TagManager rescue ActiveRecord::RecordNotFound nil end + + private + + def uri_to_local_account_params(uri) + return unless local_uri?(uri) + + path_params = Rails.application.routes.recognize_path(uri) + + # TODO: handle numeric IDs + case path_params[:controller] + when 'accounts' + [:username, path_params[:username]] + when 'instance_actors' + [:id, -99] + end + end end diff --git a/app/lib/fasp/request.rb b/app/lib/fasp/request.rb index f0c589b7a2..2addbe8502 100644 --- a/app/lib/fasp/request.rb +++ b/app/lib/fasp/request.rb @@ -53,11 +53,11 @@ class Fasp::Request def validate!(response) content_digest_header = response.headers['content-digest'] - raise SignatureVerification::SignatureVerificationError, 'content-digest missing' if content_digest_header.blank? - raise SignatureVerification::SignatureVerificationError, 'content-digest does not match' if content_digest_header != content_digest(response.body) + raise Mastodon::SignatureVerificationError, 'content-digest missing' if content_digest_header.blank? + raise Mastodon::SignatureVerificationError, 'content-digest does not match' if content_digest_header != content_digest(response.body) signature_input = response.headers['signature-input']&.encode('UTF-8') - raise SignatureVerification::SignatureVerificationError, 'signature-input is missing' if signature_input.blank? + raise Mastodon::SignatureVerificationError, 'signature-input is missing' if signature_input.blank? linzer_response = Linzer.new_response( response.body, diff --git a/app/models/poll.rb b/app/models/poll.rb index 7c59339b7e..25ce9c3be9 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -23,6 +23,8 @@ class Poll < ApplicationRecord include Expireable + MAKE_FETCH_HAPPEN = 1.minute + belongs_to :account belongs_to :status @@ -113,7 +115,7 @@ class Poll < ApplicationRecord end def time_passed_since_last_fetch? - last_fetched_at.nil? || last_fetched_at < 1.minute.ago + last_fetched_at.nil? || last_fetched_at < MAKE_FETCH_HAPPEN.ago end def show_totals_now? diff --git a/app/services/activitypub/synchronize_followers_service.rb b/app/services/activitypub/synchronize_followers_service.rb index 5b58a025cb..fd6fd1b899 100644 --- a/app/services/activitypub/synchronize_followers_service.rb +++ b/app/services/activitypub/synchronize_followers_service.rb @@ -30,10 +30,7 @@ class ActivityPub::SynchronizeFollowersService < BaseService # Account record, and should we not do that, we should have sent a Delete. # In any case there is not much we can do if that occurs. - # TODO: this will need changes when switching to numeric IDs - - usernames = items.filter_map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username)&.downcase } - Account.local.with_username(usernames) + ActivityPub::TagManager.instance.uris_to_local_accounts(items) end def remove_unexpected_local_followers! diff --git a/config/locales/br.yml b/config/locales/br.yml index f12269eba3..e61a43643e 100644 --- a/config/locales/br.yml +++ b/config/locales/br.yml @@ -79,6 +79,8 @@ br: public: Publik reject: Nac'hañ remove_header: Dilemel an talbenn + resend_confirmation: + send: Adkas al liamm-kadarnaat reset: Adderaouekaat reset_password: Adderaouekaat ar ger-tremen resubscribe: Adkoumanantiñ @@ -99,6 +101,12 @@ br: web: Web action_logs: action_types: + approve_user: Aprouiñ an implijer + change_role_user: Kemmañ perzh an implijer + confirm_user: Aprouiñ an implijer + create_ip_block: Krouiñ ur reolenn IP + create_user_role: Krouiñ ur perzh + destroy_ip_block: Dilemel ar reolenn IP destroy_status: Dilemel ar c'hannad reset_password_user: Adderaouekaat ar ger-tremen update_status: Hizivaat ar c'hannad @@ -141,12 +149,15 @@ br: export: Ezporzhiañ import: Enporzhiañ domain_blocks: + confirm_suspension: + cancel: Nullañ domain: Domani new: create: Sevel ur stanker severity: noop: Hini ebet suspend: Astalañ + public_comment: Evezhiadenn foran email_domain_blocks: add_new: Ouzhpenniñ unan nevez delete: Dilemel @@ -158,6 +169,18 @@ br: create: Ouzhpenniñ un domani export_domain_allows: no_file: Restr ebet diuzet + fasp: + debug: + callbacks: + delete: Dilemel + ip: Chomlec'h IP + providers: + active: Oberiant + delete: Dilemel + name: Anv + registrations: + confirm: Kadarnaat + status: Statud follow_recommendations: status: Statud suppressed: Dilamet @@ -172,6 +195,7 @@ br: suspend: Astalañ policy: Reolennoù dashboard: + instance_languages_dimension: Yezhoù pennañ instance_statuses_measure: toudoù stoket delivery: all: Pep tra @@ -182,6 +206,9 @@ br: title: Habaskadur purge: Spurjañ title: Kevread + total_blocked_by_us: Stanket ganeomp + total_followed_by_them: Heuliet ganto + total_followed_by_us: Heuliet ganeomp total_storage: Restroù media stag invites: filter: @@ -191,6 +218,7 @@ br: title: Sil title: Pedadennoù ip_blocks: + add_new: Krouiñ ur reolenn delete: Dilemel expires_in: '1209600': 2 sizhunvezh @@ -198,6 +226,9 @@ br: '31556952': 1 bloavezh '86400': 1 devezh '94670856': 3 bloavezh + new: + title: Krouiñ ur reolenn IP nevez + title: Reolennoù IP relays: delete: Dilemel disable: Diweredekaat @@ -218,6 +249,7 @@ br: are_you_sure: Ha sur oc'h? comment: none: Hini ebet + confirm: Kadarnaat delete_and_resolve: Dilemel ar c'hannadoù forwarded: Treuzkaset no_one_assigned: Den ebet diff --git a/config/locales/he.yml b/config/locales/he.yml index f9b2970fd0..6d575bc564 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -232,7 +232,7 @@ he: silence_account: הגבלת חשבון suspend_account: השעיית חשבון unassigned_report: ביטול הקצאת דו"ח - unblock_email_account: ביטול חסימת כתובת דוא"ל + unblock_email_account: הסרת חסימת כתובת דוא"ל unsensitive_account: ביטול Force-Sensitive לחשבון unsilence_account: ביטול השתקת חשבון unsuspend_account: ביטול השעיית חשבון @@ -263,11 +263,11 @@ he: create_user_role_html: "%{name} יצר את התפקיד של %{target}" demote_user_html: "%{name} הוריד/ה בדרגה את המשתמש %{target}" destroy_announcement_html: "%{name} מחק/ה את ההכרזה %{target}" - destroy_canonical_email_block_html: "%{name} הסיר/ה חסימה מדואל %{target}" + destroy_canonical_email_block_html: "%{name} הסירו חסימה מדואל %{target}" destroy_custom_emoji_html: "%{name} מחק אמוג'י של %{target}" destroy_domain_allow_html: "%{name} לא התיר/ה פדרציה עם הדומיין %{target}" - destroy_domain_block_html: "%{name} הסיר/ה חסימה מהדומיין %{target}" - destroy_email_domain_block_html: '%{name} הסיר/ה חסימה מדומיין הדוא"ל %{target}' + destroy_domain_block_html: החסימה על מתחם %{target} הוסרה ע"י %{name} + destroy_email_domain_block_html: הוסרה חסימת מתחם דוא"ל %{target} בידי %{name} destroy_instance_html: "%{name} טיהר/ה את הדומיין %{target}" destroy_ip_block_html: "%{name} מחק/ה את הכלל עבור IP %{target}" destroy_relay_html: "%{name} מחקו את הממסר %{target}" @@ -495,6 +495,36 @@ he: new: title: יבוא רשימת שרתים חסומים no_file: לא נבחר קובץ + fasp: + debug: + callbacks: + created_at: תאריך יצירה + delete: מחיקה + ip: כתובת IP + request_body: גוף הבקשה + title: ניפוי תקלות בקריאות חוזרות + providers: + active: פעילים + base_url: קישור בסיס + callback: קריאה חוזרת + delete: מחיקה + edit: עריכת ספק + finish_registration: סיום הרשמה + name: שם + providers: ספקים + public_key_fingerprint: טביעת האצבע של המפתח הציבורי + registration_requested: נדרשת הרשמה + registrations: + confirm: אישור + description: קיבלת הרשמה דרך FASP. יש לדחות אותה אם לא ביקשת את ההרשמה הזו מיוזמתך. אם זו בקשה מיוזמתך, יש להשוות בהקפדה אם השם וטביעת האצבע של המפתח הציבורי תואמים לפני אישור הרישום. + reject: דחיה + title: אישור הרשמת FASP + save: שמירה + select_capabilities: בחירת יכולות + sign_in: כניסה + status: מצב + title: ספקי משנה לפדיוורס + title: פרוטוקול FASP follow_recommendations: description_html: "עקבו אחר ההמלצות על מנת לעזור למשתמשים חדשים למצוא תוכן מעניין. במידה ומשתמש לא תקשר מספיק עם משתמשים אחרים כדי ליצור המלצות מעקב, חשבונות אלה יומלצו במקום. הם מחושבים מחדש על בסיסי יומיומי מתערובת של החשבונות הפעילים ביותר עם החשבונות הנעקבים ביותר עבור שפה נתונה." language: עבור שפה diff --git a/config/locales/it.yml b/config/locales/it.yml index 3bf84db54f..95096b07c8 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -479,6 +479,36 @@ it: new: title: Importare i blocchi di dominio no_file: Nessun file selezionato + fasp: + debug: + callbacks: + created_at: Creato il + delete: Cancella + ip: Indirizzo IP + request_body: Request body + title: Debug Callbacks + providers: + active: Attivo + base_url: Url di base + callback: Callback + delete: Cancella + edit: Modifica Provider + finish_registration: Registrazione terminata + name: Nome + providers: Providers + public_key_fingerprint: Chiave pubblica fingerprint + registration_requested: Registrazione richiesta + registrations: + confirm: Conferma + description: Hai ricevuto una registrazione da un FASP. Rifiutala se non l'hai avviata tu. Se l'hai avviata tu, confronta attentamente nome e impronta della chiave prima di confermare la registrazione. + reject: Rifiuta + title: Conferma registrazione FASP + save: Salva + select_capabilities: Seleziona Capacità + sign_in: Connettiti + status: Stato + title: Fornitori di Servizi Ausiliari per il Fediverso + title: FASP follow_recommendations: description_html: "I consigli su chi seguire aiutano i nuovi utenti a trovare rapidamente dei contenuti interessanti. Quando un utente non ha interagito abbastanza con altri per avere dei consigli personalizzati, vengono consigliati questi account. Sono ricalcolati ogni giorno da un misto di account con le più alte interazioni recenti e con il maggior numero di seguaci locali per una data lingua." language: Per lingua diff --git a/config/locales/kab.yml b/config/locales/kab.yml index b65109df1a..1f6fc8f698 100644 --- a/config/locales/kab.yml +++ b/config/locales/kab.yml @@ -268,6 +268,15 @@ kab: no_file: Ula d yiwen ufaylu ma yettwafran export_domain_blocks: no_file: Ulac afaylu yettwafernen + fasp: + debug: + callbacks: + delete: Kkes + ip: Tansa IP + providers: + delete: Kkes + save: Sekles + title: FASP follow_recommendations: language: I tutlayt status: Addad @@ -378,6 +387,7 @@ kab: everyone: Tisirag timezwura privileges: administrator: Anedbal + view_dashboard: Timẓriwt n tfelwit rules: add_new: Rnu alugen delete: Kkes @@ -391,6 +401,7 @@ kab: title: Udem discovery: profile_directory: Akaram n imaɣnuten + title: Asnirem trends: Ayen mucaɛen domain_blocks: all: I medden akk @@ -431,6 +442,9 @@ kab: software_version_patch_check: action: Wali ileqqman yellan tags: + name: Isem + newest: Amaynut + oldest: Aqbur search: Anadi title: Ihacṭagen terms_of_service: @@ -705,6 +719,7 @@ kab: units: billion: AṬ million: A + thousand: GM trillion: Am otp_authentication: enable: Rmed @@ -864,6 +879,7 @@ kab: warning: categories: spam: Aspam + reason: 'Taɣẓint:' title: disable: Amiḍan i igersen none: Ɣur-wat diff --git a/config/locales/lv.yml b/config/locales/lv.yml index a029dcd185..07fc9c9780 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -304,6 +304,7 @@ lv: title: Audita žurnāls unavailable_instance: "(domēna vārds nav pieejams)" announcements: + back: Atgriezties pie paziņojumiem destroyed_msg: Paziņojums sekmīgi izdzēsts. edit: title: Labot paziņojumu @@ -312,6 +313,9 @@ lv: new: create: Izveidot paziņojumu title: Jauns paziņojums + preview: + explanation_html: 'E-pasta ziņojums tiks nosūtīts %{display_count} lietotājiem. Šis teksts tiks iekļauts e-pasta ziņojumā:' + title: Priekšskatīt paziņojumu publish: Publicēt published_msg: Paziņojums sekmīgi publicēts. scheduled_for: Plānots uz %{time} @@ -455,7 +459,9 @@ lv: create: Pievienot domēnu resolve: Atrisināt domēnu title: Liegt jaunu e-pasta domēnu + no_email_domain_block_selected: Neviens e-pasta domēna bloks netika mainīts, jo neviens netika atlasīts not_permitted: Nav atļauta + resolved_dns_records_hint_html: Domēna vārds saistās ar zemāk norādītajiem MX domēniem, kuri beigās ir atbildīgi par e-pasta pieņemšana. MX domēna liegšana liegs reģistrēšanos no jebkuras e-pasta adreses, kas izmanto to pašu MX domēnu, pat ja redzamais domēna vārds ir atšķirīgs. Jāuzmanās, lai neliegtu galvenos e-pasta pakalpojuma sniedzējus. resolved_through_html: Atrisināts, izmantojot %{domain} title: Bloķētie e-pasta domēni export_domain_allows: @@ -473,6 +479,13 @@ lv: new: title: Importēt bloķētos domēnus no_file: Nav atlasīts neviens fails + fasp: + debug: + callbacks: + created_at: Izveidots + delete: Izdzēst + ip: IP adrese + request_body: Pieprasījuma saturs follow_recommendations: description_html: "Sekošanas ieteikumi palīdz jauniem lietotājiem ātri arast saistošu saturu. Kad lietotājs nav pietiekami mijiedarbojies ar citiem, lai veidotos pielāgoti sekošanas iteikumi, tiek ieteikti šie konti. Tie tiek pārskaitļoti ik dienas, izmantojot kontu, kuriem ir augstākās nesenās iesaistīšanās un lielākais vietējo sekotāju skaits norādītajā valodā." language: Valodai @@ -934,6 +947,7 @@ lv: chance_to_review_html: "Izveidotie pakalpojuma izmantošanas noteikumi netiks laisti klajā automātiski. Būs iespēja izskatīt iznākumu. Lūgums norādīt nepieciešamo informāciju, lai turpinātu." explanation_html: Pakalpojuma izmantošanas noteikumu sagatave tiek piedāvāta tikai izzināšanas nolūkam, un to nevajadzētu izmantot kā juridisku padomu jebkurā jautājumā. Lūgums sazināties ar savu juridisko padomdevēju par saviem apstākļiem un noteiktiem juridiskiem jautājumiem. title: Pakalpojuma izmantošānas noteikumu uzstādīšana + going_live_on_html: Darbībā, spēkā no %{date} history: Vēsture live: Darbībā no_history: Nav ierakstu par pakalpojuma izmantošanas noteikumu izmaiņām. @@ -1060,6 +1074,7 @@ lv: admin_mailer: auto_close_registrations: body: Nesenu satura pārraudzības darbību trūkuma dēļ reģistrācija %{instance} ir automātiski pārslēgta nepieciešamība pēc pašrocīgas izskatīšanas, lai novērstu %{instance} izmantošana kā platformu iespējami sliktiem dalībniekiem. Jebkurā brīdī var ieslēgt atpakaļ atvērtu reģistrēšanos. + subject: Reģistrēšanās %{instance} tika automātiski pārslēgta, lai pieprasītu apstiprināšanu new_appeal: actions: delete_statuses: lai izdzēstu viņu ierakstus @@ -1186,6 +1201,7 @@ lv: set_new_password: Iestatīt jaunu paroli setup: email_below_hint_html: Jāpārbauda sava surogātpasta mape vai jāpieprasa vēl vienu! Savu e-pasta adresi var labot, ja tā ir nepareiza. + email_settings_hint_html: Jāatver saite, kuru mēs nosūtījām uz %{email}, lai sāktu izmantot Mastodon. Mēs gaidīsim šeit pat. link_not_received: Vai nesaņēmi sati? new_confirmation_instructions_sent: Pēc dažām minūtēm saņemsi jaunu e-pasta ziņojumu ar apstiprinājuma saiti. title: Pārbaudi savu iesūtni @@ -1194,21 +1210,27 @@ lv: title: Pieteikties %{domain} sign_up: manual_review: Reģistrāciju %{domain} pašrocīgi izskata mūsu satura pārraudzītāji. Lai palīdzētu mums apstrādāt Tavu reģistrāciju, uzraksti mazliet par sevi un to, kāpēc vēlies kontu %{domain}! + preamble: Ar kontu šajā Mastodon serverī varēsi sekot jebkuram citam cilvēkam fediversā, neatkarīgi no tā, kur tiek mitināts viņu konts. title: Atļauj tevi iestatīt %{domain}. status: account_status: Konta statuss confirming: Gaida e-pasta adreses apstiprināšanas pabeigšanu. functional: Tavs konts ir pilnā darba kārtībā. + pending: Tavs pieteikums ir rindā uz izskatīšanu, ko veic mūsu personāls. Tas var aizņemt kādu laiku. Tu saņemsi e-pasta ziņojumu, ja Tavs pieteikums tiks apstiprināts. redirecting_to: Tavs konts ir neaktīvs, jo pašlaik tas tiek novirzīts uz %{acct}. self_destruct: Tā kā %{domain} tiek slēgts, tu iegūsi tikai ierobežotu piekļuvi savam kontam. view_strikes: Skati iepriekšējos brīdinājumus par savu kontu too_fast: Veidlapa ir iesniegta pārāk ātri, mēģini vēlreiz. use_security_key: Lietot drošības atslēgu user_agreement_html: Es esmu izlasījis un piekrītu pakalpojuma izmantošanas noteikumiem un privātuma nosacījumiem + user_privacy_agreement_html: Es izlasīju un piekrītu privātuma pamatnostādnēm author_attribution: example_title: Parauga teksts + hint_html: Vai Tu Raksti ziņu vai emuāra rakstus ārpus Mastodon? Pārraugi apliecinājumus, kad raksti tiek kopīgoti Mastodon. + instructions: 'Jāpārliecinās, ka šis kods ir raksta HTML:' more_from_html: Vairāk no %{name} s_blog: "%{name} emuāri" + then_instructions: Tad jāpievieno publicējuma domēna vārds zemāk esošajā laukā. title: Autora attiecinājums challenge: confirm: Turpināt @@ -1413,6 +1435,48 @@ lv: merge_long: Saglabāt esošos ierakstus un pievienot jaunus overwrite: Pārrakstīt overwrite_long: Nomainīt pašreizējos ierakstus ar jauniem + overwrite_preambles: + blocking_html: + one: Tu gatavojies aizstāt savu lieguma sarakstu ar līdz %{count} kontam no %{filename}. + other: Tu gatavojies aizstāt savu lieguma sarakstu ar līdz %{count} kontiem no %{filename}. + zero: Tu gatavojies aizstāt savu lieguma sarakstu ar līdz %{count} kontiem no %{filename}. + bookmarks_html: + one: Tu gatavojies aizstāt savas grāmatzīmes ar līdz %{count} ierakstam no %{filename}. + other: Tu gatavojies aizstāt savas grāmatzīmes ar līdz %{count} ierakstiem no %{filename}. + zero: Tu gatavojies aizstāt savas grāmatzīmes ar līdz %{count} ierakstiem no %{filename}. + domain_blocking_html: + one: Tu gatavojies aizstāt savu liegto domēnu sarakstu ar līdz %{count} domēnam no %{filename}. + other: Tu gatavojies aizstāt savu liegto domēnu sarakstu ar līdz %{count} domēniem no %{filename}. + zero: Tu gatavojies aizstāt savu liegto domēnu sarakstu ar līdz %{count} domēniem no %{filename}. + following_html: + one: Tu gatavojies sekot līdz %{count} kontam no %{filename} un pārtrauksi sekot citiem. + other: Tu gatavojies sekot līdz %{count} kontiem no %{filename} un pārtrauksi sekot citiem. + zero: Tu gatavojies sekot līdz %{count} kontiem no %{filename} un pārtrauksi sekot citiem. + lists_html: + one: Tu gatavojies aizstāt savus sarakstus ar %{filename} saturu. Līdz %{count} kontam tiks pievienoti jaunajos sarakstos. + other: Tu gatavojies aizstāt savus sarakstus ar %{filename} saturu. Līdz %{count} kontiem tiks pievienoti jaunajos sarakstos. + zero: Tu gatavojies aizstāt savus sarakstus ar %{filename} saturu. Līdz %{count} kontiem tiks pievienoti jaunajos sarakstos. + muting_html: + one: Tu gatavojies aizstāt savu apklusināto kontu sarakstu ar līdz %{count} kontam no %{filename}. + other: Tu gatavojies aizstāt savu apklusināto kontu sarakstu ar līdz %{count} kontiem no %{filename}. + zero: Tu gatavojies aizstāt savu apklusināto kontu sarakstu ar līdz %{count} kontiem no %{filename}. + preambles: + blocking_html: + one: Tu gatavojies liegt līdz %{count} kontam no %{filename}. + other: Tu gatavojies liegt līdz %{count} kontiem no %{filename}. + zero: Tu gatavojies liegt līdz %{count} kontiem no %{filename}. + bookmarks_html: + one: Tu gatavojies pievienot līdz %{count} ierakstam no %{filename} savām grāmatzīmēm. + other: Tu gatavojies pievienot līdz %{count} ierakstiem no %{filename} savām grāmatzīmēm. + zero: Tu gatavojies pievienot līdz %{count} ierakstiem no %{filename} savām grāmatzīmēm. + domain_blocking_html: + one: Tu gatavojies liegt līdz %{count} domēnam no %{filename}. + other: Tu gatavojies liegt līdz %{count} domēniem no %{filename}. + zero: Tu gatavojies liegt līdz %{count} domēniem no %{filename}. + following_html: + one: Tu gatavojies sekot līdz %{count} kontam no %{filename}. + other: Tu gatavojies sekot līdz %{count} kontiem no %{filename}. + zero: Tu gatavojies sekot līdz %{count} kontiem no %{filename}. preface: Tu vari ievietot datus, kurus esi izguvis no cita servera, kā, piemēram, cilvēku sarakstu, kuriem Tu seko vai kurus bloķē. recent_imports: Nesen importēts states: diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index 016ed4b25a..342a1dbe1c 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -84,7 +84,7 @@ de: backups_retention_period: Nutzer*innen haben die Möglichkeit, Archive ihrer Beiträge zu erstellen, die sie später herunterladen können. Wenn ein positiver Wert gesetzt ist, werden diese Archive nach der festgelegten Anzahl von Tagen automatisch aus deinem Speicher gelöscht. bootstrap_timeline_accounts: Diese Konten werden bei den Follower-Empfehlungen für neu registrierte Nutzer*innen oben angeheftet. closed_registrations_message: Wird angezeigt, wenn Registrierungen deaktiviert sind - content_cache_retention_period: Sämtliche Beiträge von anderen Servern (einschließlich geteilte Beiträge und Antworten) werden, unabhängig von der Interaktion der lokalen Nutzer*innen mit diesen Beiträgen, nach der festgelegten Anzahl von Tagen gelöscht. Das betrifft auch Beiträge, die von lokalen Nutzer*innen favorisiert oder als Lesezeichen gespeichert wurden. Private Erwähnungen zwischen Nutzer*innen von verschiedenen Servern werden ebenfalls verloren gehen und können nicht wiederhergestellt werden. Das Verwenden dieser Option richtet sich ausschließlich an Server für spezielle Zwecke und wird die allgemeine Nutzungserfahrung beeinträchtigen, wenn sie für den allgemeinen Gebrauch aktiviert ist. + content_cache_retention_period: Sämtliche Beiträge von anderen Servern (einschließlich geteilte Beiträge und Antworten) werden, unabhängig von der Interaktion der lokalen Nutzer*innen mit diesen Beiträgen, nach der festgelegten Anzahl von Tagen gelöscht. Das betrifft auch Beiträge, die von lokalen Nutzer*innen favorisiert oder als Lesezeichen gespeichert wurden. Private Erwähnungen zwischen Nutzer*innen von verschiedenen Servern werden ebenfalls verloren gehen und können nicht wiederhergestellt werden. Diese Option richtet sich ausschließlich an Server mit speziellen Zwecken und wird die allgemeine Nutzungserfahrung beeinträchtigen, wenn sie für den allgemeinen Gebrauch aktiviert ist. custom_css: Du kannst benutzerdefinierte Stile auf die Web-Version von Mastodon anwenden. favicon: WEBP, PNG, GIF oder JPG. Überschreibt das Standard-Mastodon-Favicon mit einem eigenen Symbol. mascot: Überschreibt die Abbildung in der erweiterten Weboberfläche. diff --git a/config/locales/simple_form.es-MX.yml b/config/locales/simple_form.es-MX.yml index 63287a3989..b768c6551f 100644 --- a/config/locales/simple_form.es-MX.yml +++ b/config/locales/simple_form.es-MX.yml @@ -75,7 +75,7 @@ es-MX: filters: action: Elegir qué acción realizar cuando una publicación coincide con el filtro actions: - blur: Ocultar contenido multimedia detrás de una advertencia, sin ocultar el texto en sí + blur: Ocultar contenido multimedia detrás de una advertencia, sin ocultar el propio texto hide: Ocultar completamente el contenido filtrado, comportándose como si no existiera warn: Ocultar el contenido filtrado detrás de una advertencia mencionando el título del filtro form_admin_settings: @@ -89,7 +89,7 @@ es-MX: favicon: WEBP, PNG, GIF o JPG. Reemplaza el icono predeterminado de Mastodon con un icono personalizado. mascot: Reemplaza la ilustración en la interfaz web avanzada. media_cache_retention_period: Los archivos multimedia de las publicaciones realizadas por usuarios remotos se almacenan en caché en su servidor. Si se establece en un valor positivo, los archivos multimedia se eliminarán tras el número de días especificado. Si los datos multimedia se solicitan después de haber sido eliminados, se volverán a descargar, si el contenido de origen sigue estando disponible. Debido a las restricciones sobre la frecuencia con la que las tarjetas de previsualización de enlaces sondean sitios de terceros, se recomienda establecer este valor en al menos 14 días, o las tarjetas de previsualización de enlaces no se actualizarán bajo demanda antes de ese tiempo. - min_age: Se pedirá a los usuarios que confirmen su fecha de nacimiento durante el registro + min_age: Se pedirá a los usuarios que confirmen su fecha de nacimiento al registrarse peers_api_enabled: Una lista de nombres de dominio que este servidor ha encontrado en el fediverso. Aquí no se incluye ningún dato sobre si usted federa con un servidor determinado, sólo que su servidor lo sabe. Esto es utilizado por los servicios que recopilan estadísticas sobre la federación en un sentido general. profile_directory: El directorio de perfiles lista a todos los usuarios que han optado por que su cuenta pueda ser descubierta. require_invite_text: Cuando los registros requieren aprobación manual, hace obligatoria la entrada de texto "¿Por qué quieres unirte?" en lugar de opcional @@ -145,10 +145,10 @@ es-MX: dmca_email: Puede ser el mismo correo electrónico utilizado para "Dirección de correo electrónico para avisos legales" de arriba. domain: Identificación única del servicio en línea que presta. jurisdiction: Indique el país de residencia de quien paga las facturas. Si se trata de una empresa u otra entidad, indique el país en el que está constituida y la ciudad, región, territorio o estado, según proceda. - min_age: No debería estar por debajo de la edad mínima requerida por las leyes de su jurisdicción. + min_age: No debe ser menor de la edad mínima exigida por las leyes de su jurisdicción. user: chosen_languages: Cuando se marca, solo se mostrarán las publicaciones en los idiomas seleccionados en las líneas de tiempo públicas - date_of_birth: Tenemos que asegurarnos de que al menos tienes %{age} años para usar Mastodon. No almacenaremos esta información. + date_of_birth: Tenemos que asegurarnos de que tienes al menos %{age} para usar Mastodon. No almacenaremos esto. role: El rol controla qué permisos tiene el usuario. user_role: color: Color que se usará para el rol en toda la interfaz de usuario, como RGB en formato hexadecimal diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 8437dacf5e..d943462d0c 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -480,6 +480,34 @@ tr: title: Domain bloklarını içe aktar no_file: Dosya seçilmedi fasp: + debug: + callbacks: + created_at: Oluşturulma tarihi + delete: Sil + ip: IP adresi + request_body: İstek gövdesi + title: Hata ayıklama geri çağrıları + providers: + active: Etkin + base_url: Temel URL + callback: Geri çağırma + delete: Sil + edit: Sağlayıcıyı Düzenle + finish_registration: Kaydı tamamla + name: Ad + providers: Sağlayıcılar + public_key_fingerprint: Açık anahtar parmak izi + registration_requested: Kayıt istendi + registrations: + confirm: Onayla + description: FASP'tan bir kayıt aldınız. Eğer bunu siz başlatmadıysanız reddedin. Eğer siz başlattıysanız, kaydı onaylamadan önce ad ve anahtar parmak izini dikkatlice karşılaştırın. + reject: Reddet + title: FASP Kaydını Onayla + save: Kaydet + select_capabilities: Yetenekleri Seç + sign_in: Oturum Aç + status: Durum + title: Fediverse Yardımcı Hizmet Sağlayıcıları (FASP) title: FASP follow_recommendations: description_html: "Takip önerileri yeni kullanıcıların hızlı bir şekilde ilginç içerik bulmalarını sağlar. Eğer bir kullanıcı, kişisel takip önerileri almaya yetecek kadar başkalarıyla etkileşime girmediğinde, onun yerine bu hesaplar önerilir. Bu öneriler, verili bir dil için en yüksek takipçi sayısına ve en yüksek güncel meşguliyete sahip hesapların bir karışımdan günlük olarak hesaplanıyorlar." diff --git a/lib/exceptions.rb b/lib/exceptions.rb index 135f8126a4..93fcc38dce 100644 --- a/lib/exceptions.rb +++ b/lib/exceptions.rb @@ -12,6 +12,7 @@ module Mastodon class RateLimitExceededError < Error; end class SyntaxError < Error; end class InvalidParameterError < Error; end + class SignatureVerificationError < Error; end class UnexpectedResponseError < Error attr_reader :response diff --git a/package.json b/package.json index c3b67841af..78cb5b2a73 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/mastodon", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.7.0", + "packageManager": "yarn@4.8.1", "engines": { "node": ">=18" }, @@ -151,7 +151,7 @@ "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^16.0.0", "@types/babel__core": "^7.20.1", - "@types/emoji-mart": "^3.0.9", + "@types/emoji-mart": "3.0.14", "@types/escape-html": "^1.0.2", "@types/hoist-non-react-statics": "^3.3.1", "@types/http-link-header": "^1.0.3", @@ -197,7 +197,7 @@ "stylelint": "^16.11.0", "stylelint-config-prettier-scss": "^1.0.0", "stylelint-config-standard-scss": "^14.0.0", - "typescript": "^5.0.4", + "typescript": "~5.7.3", "typescript-eslint": "^8.28.0", "webpack-dev-server": "^3.11.3" }, diff --git a/spec/controllers/settings/pictures_controller_spec.rb b/spec/controllers/settings/pictures_controller_spec.rb deleted file mode 100644 index 683d231ed1..0000000000 --- a/spec/controllers/settings/pictures_controller_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Settings::PicturesController do - render_views - - let!(:user) { Fabricate(:user) } - - before do - sign_in user, scope: :user - end - - describe 'DELETE #destroy' do - context 'with invalid picture id' do - it 'returns http bad request' do - delete :destroy, params: { id: 'invalid' } - expect(response).to have_http_status(400) - end - end - - context 'with valid picture id' do - context 'when account updates correctly' do - let(:service) { instance_double(UpdateAccountService, call: true) } - - before do - allow(UpdateAccountService).to receive(:new).and_return(service) - end - - it 'updates the account' do - delete :destroy, params: { id: 'avatar' } - expect(response).to redirect_to(settings_profile_path) - expect(response).to have_http_status(303) - expect(service).to have_received(:call).with(user.account, { 'avatar' => nil, 'avatar_remote_url' => '' }) - end - end - - context 'when account cannot update' do - let(:service) { instance_double(UpdateAccountService, call: false) } - - before do - allow(UpdateAccountService).to receive(:new).and_return(service) - end - - it 'redirects to profile' do - delete :destroy, params: { id: 'avatar' } - expect(response).to redirect_to(settings_profile_path) - end - end - end - end -end diff --git a/spec/helpers/admin/trends/statuses_helper_spec.rb b/spec/helpers/admin/trends/statuses_helper_spec.rb index fa5c337e97..6abc4569b4 100644 --- a/spec/helpers/admin/trends/statuses_helper_spec.rb +++ b/spec/helpers/admin/trends/statuses_helper_spec.rb @@ -28,6 +28,19 @@ RSpec.describe Admin::Trends::StatusesHelper do end end + context 'with a remote status that has excessive attributes' do + let(:attr_limit) { Nokogiri::Gumbo::DEFAULT_MAX_ATTRIBUTES * 2 } + let(:html) { "

text

" } + + let(:status) { Fabricate.build(:status, uri: 'https://host.example', text: html) } + + it 'renders a correct preview text' do + result = helper.one_line_preview(status) + + expect(result).to eq '' + end + end + context 'with a status that has empty text' do let(:status) { Fabricate.build(:status, text: '') } diff --git a/spec/lib/activitypub/tag_manager_spec.rb b/spec/lib/activitypub/tag_manager_spec.rb index 4dcfc69824..7a4cf3c1b8 100644 --- a/spec/lib/activitypub/tag_manager_spec.rb +++ b/spec/lib/activitypub/tag_manager_spec.rb @@ -187,6 +187,23 @@ RSpec.describe ActivityPub::TagManager do end end + describe '#uris_to_local_accounts' do + it 'returns the expected local accounts' do + account = Fabricate(:account) + expect(subject.uris_to_local_accounts([subject.uri_for(account), instance_actor_url])).to contain_exactly(account, Account.representative) + end + + it 'does not return remote accounts' do + account = Fabricate(:account, uri: 'https://example.com/123', domain: 'example.com') + expect(subject.uris_to_local_accounts([subject.uri_for(account)])).to be_empty + end + + it 'does not return an account for a local post' do + status = Fabricate(:status) + expect(subject.uris_to_local_accounts([subject.uri_for(status)])).to be_empty + end + end + describe '#uri_to_resource' do it 'returns the local account' do account = Fabricate(:account) diff --git a/spec/lib/fasp/request_spec.rb b/spec/lib/fasp/request_spec.rb index ab1265e14f..5d81c09722 100644 --- a/spec/lib/fasp/request_spec.rb +++ b/spec/lib/fasp/request_spec.rb @@ -38,7 +38,7 @@ RSpec.describe Fasp::Request do it 'raises an error' do expect do subject.send(method, '/test_path') - end.to raise_error(SignatureVerification::SignatureVerificationError) + end.to raise_error(Mastodon::SignatureVerificationError) end end end diff --git a/spec/requests/settings/pictures_spec.rb b/spec/requests/settings/pictures_spec.rb new file mode 100644 index 0000000000..f297eb3649 --- /dev/null +++ b/spec/requests/settings/pictures_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Settings Pictures' do + let!(:user) { Fabricate(:user) } + + before { sign_in user } + + describe 'DELETE /settings/profile/pictures/:id' do + context 'with invalid picture id' do + it 'returns http bad request' do + delete settings_profile_picture_path(id: 'invalid') + + expect(response) + .to have_http_status(400) + end + end + + context 'with valid picture id' do + before { stub_service } + + context 'when account updates correctly' do + let(:service) { instance_double(UpdateAccountService, call: true) } + + it 'updates the account' do + delete settings_profile_picture_path(id: 'avatar') + + expect(response) + .to redirect_to(settings_profile_path) + .and have_http_status(303) + expect(service) + .to have_received(:call).with(user.account, { 'avatar' => nil, 'avatar_remote_url' => '' }) + end + end + + context 'when account cannot update' do + let(:service) { instance_double(UpdateAccountService, call: false) } + + it 'redirects to profile' do + delete settings_profile_picture_path(id: 'avatar') + + expect(response) + .to redirect_to(settings_profile_path) + end + end + + def stub_service + allow(UpdateAccountService) + .to receive(:new) + .and_return(service) + end + end + end +end diff --git a/streaming/package.json b/streaming/package.json index a96a3f8c52..f376b89c3a 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/streaming", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.7.0", + "packageManager": "yarn@4.8.1", "engines": { "node": ">=18" }, @@ -39,7 +39,7 @@ "@types/ws": "^8.5.9", "globals": "^16.0.0", "pino-pretty": "^13.0.0", - "typescript": "^5.0.4", + "typescript": "~5.7.3", "typescript-eslint": "^8.28.0" }, "optionalDependencies": { diff --git a/yarn.lock b/yarn.lock index a64eb94e05..89e25ba867 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2190,14 +2190,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.10.0": - version: 4.10.0 - resolution: "@eslint-community/regexpp@npm:4.10.0" - checksum: 10c0/c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4 - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.12.1": +"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.12.1": version: 4.12.1 resolution: "@eslint-community/regexpp@npm:4.12.1" checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6 @@ -2848,7 +2841,7 @@ __metadata: "@testing-library/jest-dom": "npm:^6.0.0" "@testing-library/react": "npm:^16.0.0" "@types/babel__core": "npm:^7.20.1" - "@types/emoji-mart": "npm:^3.0.9" + "@types/emoji-mart": "npm:3.0.14" "@types/escape-html": "npm:^1.0.2" "@types/hoist-non-react-statics": "npm:^3.3.1" "@types/http-link-header": "npm:^1.0.3" @@ -2970,7 +2963,7 @@ __metadata: tesseract.js: "npm:^6.0.0" tiny-queue: "npm:^0.2.1" twitter-text: "npm:3.1.0" - typescript: "npm:^5.0.4" + typescript: "npm:~5.7.3" typescript-eslint: "npm:^8.28.0" use-debounce: "npm:^10.0.0" webpack: "npm:^4.47.0" @@ -3019,7 +3012,7 @@ __metadata: pino-http: "npm:^10.0.0" pino-pretty: "npm:^13.0.0" prom-client: "npm:^15.0.0" - typescript: "npm:^5.0.4" + typescript: "npm:~5.7.3" typescript-eslint: "npm:^8.28.0" utf-8-validate: "npm:^6.0.3" uuid: "npm:^11.0.0" @@ -3822,7 +3815,7 @@ __metadata: languageName: node linkType: hard -"@types/emoji-mart@npm:^3.0.9": +"@types/emoji-mart@npm:3.0.14": version: 3.0.14 resolution: "@types/emoji-mart@npm:3.0.14" dependencies: @@ -3848,10 +3841,10 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.5 - resolution: "@types/estree@npm:1.0.5" - checksum: 10c0/b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d +"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": + version: 1.0.7 + resolution: "@types/estree@npm:1.0.7" + checksum: 10c0/be815254316882f7c40847336cd484c3bc1c3e34f710d197160d455dc9d6d050ffbf4c3bc76585dba86f737f020ab20bdb137ebe0e9116b0c86c7c0342221b8c languageName: node linkType: hard @@ -3862,13 +3855,6 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:^1.0.6": - version: 1.0.7 - resolution: "@types/estree@npm:1.0.7" - checksum: 10c0/be815254316882f7c40847336cd484c3bc1c3e34f710d197160d455dc9d6d050ffbf4c3bc76585dba86f737f020ab20bdb137ebe0e9116b0c86c7c0342221b8c - languageName: node - linkType: hard - "@types/express-serve-static-core@npm:^4.17.33": version: 4.17.41 resolution: "@types/express-serve-static-core@npm:4.17.41" @@ -4054,16 +4040,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*": - version: 22.8.6 - resolution: "@types/node@npm:22.8.6" - dependencies: - undici-types: "npm:~6.19.8" - checksum: 10c0/d3a11f2549234a91a4c5d0ff35ab4bdcb7ba34db4d3f1d189be39b8bd41c19aac98d117150a95a9c5a9d45b1014135477ea240b2b8317c86ae3d3cf1c3b3f8f4 - languageName: node - linkType: hard - -"@types/node@npm:^22.0.0": +"@types/node@npm:*, @types/node@npm:^22.0.0": version: 22.13.14 resolution: "@types/node@npm:22.13.14" dependencies: @@ -4908,16 +4885,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.4, acorn@npm:^8.1.0, acorn@npm:^8.12.0, acorn@npm:^8.8.1, acorn@npm:^8.8.2": - version: 8.12.1 - resolution: "acorn@npm:8.12.1" - bin: - acorn: bin/acorn - checksum: 10c0/51fb26cd678f914e13287e886da2d7021f8c2bc0ccc95e03d3e0447ee278dd3b40b9c57dc222acd5881adcf26f3edc40901a4953403232129e3876793cd17386 - languageName: node - linkType: hard - -"acorn@npm:^8.14.0": +"acorn@npm:^8.0.4, acorn@npm:^8.1.0, acorn@npm:^8.14.0, acorn@npm:^8.8.1, acorn@npm:^8.8.2": version: 8.14.1 resolution: "acorn@npm:8.14.1" bin: @@ -6860,18 +6828,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.3": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10c0/5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -8384,7 +8341,7 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^4.0.0, eslint-visitor-keys@npm:^4.2.0": +"eslint-visitor-keys@npm:^4.2.0": version: 4.2.0 resolution: "eslint-visitor-keys@npm:4.2.0" checksum: 10c0/2ed81c663b147ca6f578312919483eb040295bbab759e5a371953456c636c5b49a559883e2677112453728d66293c0a4c90ab11cab3428cf02a0236d2e738269 @@ -8441,7 +8398,7 @@ __metadata: languageName: node linkType: hard -"espree@npm:^10.0.1, espree@npm:^10.3.0": +"espree@npm:^10.0.1, espree@npm:^10.1.0, espree@npm:^10.3.0": version: 10.3.0 resolution: "espree@npm:10.3.0" dependencies: @@ -8452,17 +8409,6 @@ __metadata: languageName: node linkType: hard -"espree@npm:^10.1.0": - version: 10.1.0 - resolution: "espree@npm:10.1.0" - dependencies: - acorn: "npm:^8.12.0" - acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^4.0.0" - checksum: 10c0/52e6feaa77a31a6038f0c0e3fce93010a4625701925b0715cd54a2ae190b3275053a0717db698697b32653788ac04845e489d6773b508d6c2e8752f3c57470a0 - languageName: node - linkType: hard - "esprima@npm:^4.0.0, esprima@npm:^4.0.1": version: 4.0.1 resolution: "esprima@npm:4.0.1" @@ -15133,15 +15079,15 @@ __metadata: linkType: hard "react-textarea-autosize@npm:^8.4.1": - version: 8.5.8 - resolution: "react-textarea-autosize@npm:8.5.8" + version: 8.5.9 + resolution: "react-textarea-autosize@npm:8.5.9" dependencies: "@babel/runtime": "npm:^7.20.13" use-composed-ref: "npm:^1.3.0" use-latest: "npm:^1.2.1" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/3d7add9773fd3dc189a6668efb82c1d2d5238ee5b7e933204f5f7da9df8daef81df50b36ca573a57beaa31b2727c6176ea806422790ad23be6cf7f5a5f71bbb9 + checksum: 10c0/3a924db59259a6e3b834dcddc12a8661b43dcdaa1b43c41c732e0548bb2761e9a53dbc6db4e0d9e237728b4869e42c25e5417408b0391aec290c90874733a09f languageName: node linkType: hard @@ -15816,8 +15762,8 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.86.0 - resolution: "sass@npm:1.86.0" + version: 1.86.3 + resolution: "sass@npm:1.86.3" dependencies: "@parcel/watcher": "npm:^2.4.1" chokidar: "npm:^4.0.0" @@ -15828,7 +15774,7 @@ __metadata: optional: true bin: sass: sass.js - checksum: 10c0/921caea1fd8a450d4a986e5570ce13c4ca7b2a57da390811add3d2087ad8f46f53b34652ddcb237d8bdaad49c560b8d6eee130c733c787d058bc5a71a914c139 + checksum: 10c0/ba819a0828f732adf7a94cd8ca017bce92bc299ffb878836ed1da80a30612bfbbf56a5e42d6dff3ad80d919c2025afb42948fc7b54a7bc61a9a2d58e1e0c558a languageName: node linkType: hard @@ -15941,16 +15887,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3": - version: 7.6.3 - resolution: "semver@npm:7.6.3" - bin: - semver: bin/semver.js - checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf - languageName: node - linkType: hard - -"semver@npm:^7.7.1": +"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3, semver@npm:^7.7.1": version: 7.7.1 resolution: "semver@npm:7.7.1" bin: @@ -17604,14 +17541,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.4.0, tslib@npm:^2.6.2": - version: 2.8.0 - resolution: "tslib@npm:2.8.0" - checksum: 10c0/31e4d14dc1355e9b89e4d3c893a18abb7f90b6886b089c2da91224d0a7752c79f3ddc41bc1aa0a588ac895bd97bb99c5bc2bfdb2f86de849f31caeb3ba79bbe5 - languageName: node - linkType: hard - -"tslib@npm:^2.8.0": +"tslib@npm:^2.0.0, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -17751,16 +17681,6 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.0.4": - version: 5.7.3 - resolution: "typescript@npm:5.7.3" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/b7580d716cf1824736cc6e628ab4cd8b51877408ba2be0869d2866da35ef8366dd6ae9eb9d0851470a39be17cbd61df1126f9e211d8799d764ea7431d5435afa - languageName: node - linkType: hard - "typescript@npm:^5.6.0": version: 5.8.2 resolution: "typescript@npm:5.8.2" @@ -17771,13 +17691,13 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.0.4#optional!builtin": +"typescript@npm:~5.7.3": version: 5.7.3 - resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin::version=5.7.3&hash=5786d5" + resolution: "typescript@npm:5.7.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/6fd7e0ed3bf23a81246878c613423730c40e8bdbfec4c6e4d7bf1b847cbb39076e56ad5f50aa9d7ebd89877999abaee216002d3f2818885e41c907caaa192cc4 + checksum: 10c0/b7580d716cf1824736cc6e628ab4cd8b51877408ba2be0869d2866da35ef8366dd6ae9eb9d0851470a39be17cbd61df1126f9e211d8799d764ea7431d5435afa languageName: node linkType: hard @@ -17791,6 +17711,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A~5.7.3#optional!builtin": + version: 5.7.3 + resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin::version=5.7.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/6fd7e0ed3bf23a81246878c613423730c40e8bdbfec4c6e4d7bf1b847cbb39076e56ad5f50aa9d7ebd89877999abaee216002d3f2818885e41c907caaa192cc4 + languageName: node + linkType: hard + "unbox-primitive@npm:^1.1.0": version: 1.1.0 resolution: "unbox-primitive@npm:1.1.0" @@ -17817,13 +17747,6 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~6.19.8": - version: 6.19.8 - resolution: "undici-types@npm:6.19.8" - checksum: 10c0/078afa5990fba110f6824823ace86073b4638f1d5112ee26e790155f481f2a868cc3e0615505b6f4282bdf74a3d8caad715fd809e870c2bb0704e3ea6082f344 - languageName: node - linkType: hard - "undici-types@npm:~6.20.0": version: 6.20.0 resolution: "undici-types@npm:6.20.0"