diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index 5724dbaea..12c7dd2b0 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -71,11 +71,12 @@ class Api::V1::AccountsController < ApiController def block BlockService.new.call(current_user.account, @account) - @following = { @account.id => false } - @followed_by = { @account.id => false } - @blocking = { @account.id => true } - @requested = { @account.id => false } - @muting = { @account.id => current_user.account.muting?(@account.id) } + @following = { @account.id => false } + @followed_by = { @account.id => false } + @blocking = { @account.id => true } + @requested = { @account.id => false } + @muting = { @account.id => current_account.muting?(@account.id) } + @domain_blocking = { @account.id => current_account.domain_blocking?(@account.domain) } render :relationship end @@ -107,12 +108,13 @@ class Api::V1::AccountsController < ApiController def relationships ids = params[:id].is_a?(Enumerable) ? params[:id].map(&:to_i) : [params[:id].to_i] - @accounts = Account.where(id: ids).select('id') - @following = Account.following_map(ids, current_user.account_id) - @followed_by = Account.followed_by_map(ids, current_user.account_id) - @blocking = Account.blocking_map(ids, current_user.account_id) - @muting = Account.muting_map(ids, current_user.account_id) - @requested = Account.requested_map(ids, current_user.account_id) + @accounts = Account.where(id: ids).select('id') + @following = Account.following_map(ids, current_user.account_id) + @followed_by = Account.followed_by_map(ids, current_user.account_id) + @blocking = Account.blocking_map(ids, current_user.account_id) + @muting = Account.muting_map(ids, current_user.account_id) + @requested = Account.requested_map(ids, current_user.account_id) + @domain_blocking = Account.domain_blocking_map(ids, current_user.account_id) end def search @@ -128,11 +130,12 @@ class Api::V1::AccountsController < ApiController end def set_relationship - @following = Account.following_map([@account.id], current_user.account_id) - @followed_by = Account.followed_by_map([@account.id], current_user.account_id) - @blocking = Account.blocking_map([@account.id], current_user.account_id) - @muting = Account.muting_map([@account.id], current_user.account_id) - @requested = Account.requested_map([@account.id], current_user.account_id) + @following = Account.following_map([@account.id], current_user.account_id) + @followed_by = Account.followed_by_map([@account.id], current_user.account_id) + @blocking = Account.blocking_map([@account.id], current_user.account_id) + @muting = Account.muting_map([@account.id], current_user.account_id) + @requested = Account.requested_map([@account.id], current_user.account_id) + @domain_blocking = Account.domain_blocking_map([@account.id], current_user.account_id) end def pagination_params(core_params) diff --git a/app/controllers/api/v1/domain_blocks_controller.rb b/app/controllers/api/v1/domain_blocks_controller.rb index e14547911..f223dd16e 100644 --- a/app/controllers/api/v1/domain_blocks_controller.rb +++ b/app/controllers/api/v1/domain_blocks_controller.rb @@ -17,7 +17,7 @@ class Api::V1::DomainBlocksController < ApiController end def create - current_account.block_domain!(domain_block_params[:domain]) + BlockDomainFromAccountService.new.call(current_account, domain_block_params[:domain]) render_empty end diff --git a/app/javascript/mastodon/actions/domain_blocks.js b/app/javascript/mastodon/actions/domain_blocks.js new file mode 100644 index 000000000..c88498117 --- /dev/null +++ b/app/javascript/mastodon/actions/domain_blocks.js @@ -0,0 +1,117 @@ +import api, { getLinks } from '../api' + +export const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST'; +export const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS'; +export const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL'; + +export const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST'; +export const DOMAIN_UNBLOCK_SUCCESS = 'DOMAIN_UNBLOCK_SUCCESS'; +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 function blockDomain(domain, accountId) { + return (dispatch, getState) => { + dispatch(blockDomainRequest(domain)); + + api(getState).post('/api/v1/domain_blocks', { domain }).then(response => { + dispatch(blockDomainSuccess(domain, accountId)); + }).catch(err => { + dispatch(blockDomainFail(domain, err)); + }); + }; +}; + +export function blockDomainRequest(domain) { + return { + type: DOMAIN_BLOCK_REQUEST, + domain + }; +}; + +export function blockDomainSuccess(domain, accountId) { + return { + type: DOMAIN_BLOCK_SUCCESS, + domain, + accountId + }; +}; + +export function blockDomainFail(domain, error) { + return { + type: DOMAIN_BLOCK_FAIL, + domain, + error + }; +}; + +export function unblockDomain(domain, accountId) { + return (dispatch, getState) => { + dispatch(unblockDomainRequest(domain)); + + api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(response => { + dispatch(unblockDomainSuccess(domain, accountId)); + }).catch(err => { + dispatch(unblockDomainFail(domain, err)); + }); + }; +}; + +export function unblockDomainRequest(domain) { + return { + type: DOMAIN_UNBLOCK_REQUEST, + domain + }; +}; + +export function unblockDomainSuccess(domain, accountId) { + return { + type: DOMAIN_UNBLOCK_SUCCESS, + domain, + accountId + }; +}; + +export function unblockDomainFail(domain, error) { + return { + type: DOMAIN_UNBLOCK_FAIL, + domain, + error + }; +}; + +export function fetchDomainBlocks() { + return (dispatch, getState) => { + dispatch(fetchDomainBlocksRequest()); + + api(getState).get().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 + }; +}; diff --git a/app/javascript/mastodon/features/account/components/action_bar.js b/app/javascript/mastodon/features/account/components/action_bar.js index 44ed8af7d..1997bf7b7 100644 --- a/app/javascript/mastodon/features/account/components/action_bar.js +++ b/app/javascript/mastodon/features/account/components/action_bar.js @@ -15,7 +15,9 @@ const messages = defineMessages({ mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, follow: { id: 'account.follow', defaultMessage: 'Follow' }, report: { id: 'account.report', defaultMessage: 'Report @{name}' }, - disclaimer: { id: 'account.disclaimer', defaultMessage: 'This user is from another instance. This number may be larger.' } + disclaimer: { id: 'account.disclaimer', defaultMessage: 'This user is from another instance. This number may be larger.' }, + blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' }, + unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' }, }); class ActionBar extends React.PureComponent { @@ -28,6 +30,8 @@ class ActionBar extends React.PureComponent { onMention: PropTypes.func.isRequired, onReport: PropTypes.func.isRequired, onMute: PropTypes.func.isRequired, + onBlockDomain: PropTypes.func.isRequired, + onUnblockDomain: PropTypes.func.isRequired, intl: PropTypes.object.isRequired }; @@ -59,7 +63,16 @@ class ActionBar extends React.PureComponent { } if (account.get('acct') !== account.get('username')) { + const domain = account.get('acct').split('@')[1]; extraInfo = *; + + menu.push(null); + + if (account.getIn(['relationship', 'domain_blocking'])) { + menu.push({ text: intl.formatMessage(messages.unblockDomain, { domain }), action: this.props.onUnblockDomain }); + } else { + menu.push({ text: intl.formatMessage(messages.blockDomain, { domain }), action: this.props.onBlockDomain }); + } } return ( diff --git a/app/javascript/mastodon/features/account_timeline/components/header.js b/app/javascript/mastodon/features/account_timeline/components/header.js index d7226d9b2..f1a0e8d77 100644 --- a/app/javascript/mastodon/features/account_timeline/components/header.js +++ b/app/javascript/mastodon/features/account_timeline/components/header.js @@ -15,7 +15,9 @@ class Header extends ImmutablePureComponent { onBlock: PropTypes.func.isRequired, onMention: PropTypes.func.isRequired, onReport: PropTypes.func.isRequired, - onMute: PropTypes.func.isRequired + onMute: PropTypes.func.isRequired, + onBlockDomain: PropTypes.func.isRequired, + onUnblockDomain: PropTypes.func.isRequired, }; static contextTypes = { @@ -43,6 +45,22 @@ class Header extends ImmutablePureComponent { this.props.onMute(this.props.account); } + handleBlockDomain = () => { + const domain = this.props.account.get('acct').split('@')[1]; + + if (!domain) return; + + this.props.onBlockDomain(domain, this.props.account.get('id')); + } + + handleUnblockDomain = () => { + const domain = this.props.account.get('acct').split('@')[1]; + + if (!domain) return; + + this.props.onUnblockDomain(domain, this.props.account.get('id')); + } + render () { const { account, me } = this.props; @@ -65,6 +83,8 @@ class Header extends ImmutablePureComponent { onMention={this.handleMention} onReport={this.handleReport} onMute={this.handleMute} + onBlockDomain={this.handleBlockDomain} + onUnblockDomain={this.handleUnblockDomain} /> ); diff --git a/app/javascript/mastodon/features/account_timeline/containers/header_container.js b/app/javascript/mastodon/features/account_timeline/containers/header_container.js index 50999d2e0..0964efdcf 100644 --- a/app/javascript/mastodon/features/account_timeline/containers/header_container.js +++ b/app/javascript/mastodon/features/account_timeline/containers/header_container.js @@ -13,11 +13,13 @@ import { import { mentionCompose } from '../../../actions/compose'; import { initReport } from '../../../actions/reports'; import { openModal } from '../../../actions/modal'; +import { blockDomain, unblockDomain } from '../../../actions/domain_blocks'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; const messages = defineMessages({ blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' }, - muteConfirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' } + muteConfirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' }, + blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' }, }); const makeMapStateToProps = () => { @@ -70,6 +72,18 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ onConfirm: () => dispatch(muteAccount(account.get('id'))) })); } + }, + + onBlockDomain (domain, accountId) { + dispatch(openModal('CONFIRM', { + message: {domain} }} />, + confirm: intl.formatMessage(messages.blockDomainConfirm), + onConfirm: () => dispatch(blockDomain(domain, accountId)) + })); + }, + + onUnblockDomain (domain, accountId) { + dispatch(unblockDomain(domain, accountId)); } }); diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index e30b7e84a..2a9d00460 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -1,17 +1,20 @@ { "account.block": "حظر @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "هذا المستخدم من مثيل خادم آخر. قد يكون هذا الرقم أكبر.", "account.edit_profile": "تعديل الملف الشخصي", "account.follow": "تابِع", "account.followers": "المتابعون", "account.follows": "يتبع", "account.follows_you": "يتابعك", + "account.media": "Media", "account.mention": "أُذكُر @{name}", "account.mute": "أكتم @{name}", "account.posts": "المشاركات", "account.report": "أبلغ عن @{name}", "account.requested": "في انتظار الموافقة", "account.unblock": "إلغاء الحظر عن @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "إلغاء المتابعة", "account.unmute": "إلغاء الكتم عن @{name}", "boost_modal.combo": "يمكنك ضغط {combo} لتخطّي هذه في المرّة القادمة", @@ -40,6 +43,8 @@ "confirmations.block.message": "هل أنت متأكد أنك تريد حجب {name} ؟", "confirmations.delete.confirm": "حذف", "confirmations.delete.message": "هل أنت متأكد أنك تريد حذف هذا المنشور ؟", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "أكتم", "confirmations.mute.message": "هل أنت متأكد أنك تريد كتم {name} ؟", "emoji_button.activity": "الأنشطة", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 3ca2f7775..a43cd3dab 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -1,17 +1,20 @@ { "account.block": "Блокирай", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "This user is from another instance. This number may be larger.", "account.edit_profile": "Редактирай профила си", "account.follow": "Последвай", "account.followers": "Последователи", "account.follows": "Следвам", "account.follows_you": "Твой последовател", + "account.media": "Media", "account.mention": "Споменаване", "account.mute": "Mute @{name}", "account.posts": "Публикации", "account.report": "Report @{name}", "account.requested": "В очакване на одобрение", "account.unblock": "Не блокирай", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Не следвай", "account.unmute": "Unmute @{name}", "boost_modal.combo": "You can press {combo} to skip this next time", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index f239a3d2f..61827220e 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -1,17 +1,20 @@ { "account.block": "Bloquejar @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Aquest usuari és d'un altra instància. Aquest número podria ser més gran.", "account.edit_profile": "Editar perfil", "account.follow": "Seguir", "account.followers": "Seguidors", "account.follows": "Seguint", "account.follows_you": "et segueix", + "account.media": "Media", "account.mention": "Esmentar @{name}", "account.mute": "Silenciar @{name}", "account.posts": "Publicacions", "account.report": "Informe @{name}", "account.requested": "Esperant aprovació", "account.unblock": "Desbloquejar @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Deixar de seguir", "account.unmute": "Treure silenci de @{name}", "boost_modal.combo": "Pots premer {combo} per saltar-te això el proper cop", @@ -40,6 +43,8 @@ "confirmations.block.message": "Estàs segur que vols bloquejar {name}?", "confirmations.delete.confirm": "Esborrar", "confirmations.delete.message": "Estàs segur que vols esborrar aquest estat?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Silenciar", "confirmations.mute.message": "Estàs segur que vols silenciar {name}?", "emoji_button.activity": "Activitat", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 8a5b5e418..a82bee22d 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -1,17 +1,20 @@ { "account.block": "@{name} blocken", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Dieser Benutzer ist von einer anderen Instanz. Diese Zahl könnte größer sein.", "account.edit_profile": "Profil bearbeiten", "account.follow": "Folgen", "account.followers": "Folgende", "account.follows": "Folgt", "account.follows_you": "Folgt dir", + "account.media": "Media", "account.mention": "@{name} erwähnen", "account.mute": "@{name} stummschalten", "account.posts": "Beiträge", "account.report": "@{name} melden", "account.requested": "Warte auf Erlaubnis", "account.unblock": "@{name} entblocken", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Entfolgen", "account.unmute": "@{name} nicht mehr stummschalten", "boost_modal.combo": "Du kannst {combo} drücken, um dies beim nächsten Mal zu überspringen", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index 38d76828d..67c7cc527 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -240,6 +240,15 @@ ], "path": "app/javascript/mastodon/containers/status_container.json" }, + { + "descriptors": [ + { + "defaultMessage": "Media", + "id": "account.media" + } + ], + "path": "app/javascript/mastodon/features/account_gallery/index.json" + }, { "descriptors": [ { @@ -250,6 +259,10 @@ "defaultMessage": "Mute", "id": "confirmations.mute.confirm" }, + { + "defaultMessage": "Hide entire domain", + "id": "confirmations.domain_block.confirm" + }, { "defaultMessage": "Are you sure you want to block {name}?", "id": "confirmations.block.message" @@ -257,6 +270,10 @@ { "defaultMessage": "Are you sure you want to mute {name}?", "id": "confirmations.mute.message" + }, + { + "defaultMessage": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", + "id": "confirmations.domain_block.message" } ], "path": "app/javascript/mastodon/features/account_timeline/containers/header_container.json" @@ -303,6 +320,14 @@ "defaultMessage": "This user is from another instance. This number may be larger.", "id": "account.disclaimer" }, + { + "defaultMessage": "Hide everything from {domain}", + "id": "account.block_domain" + }, + { + "defaultMessage": "Unhide {domain}", + "id": "account.unblock_domain" + }, { "defaultMessage": "Posts", "id": "account.posts" diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index f4a6a7512..6864123ae 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -1,17 +1,20 @@ { "account.block": "Block @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "This user is from another instance. This number may be larger.", "account.edit_profile": "Edit profile", "account.follow": "Follow", "account.followers": "Followers", "account.follows": "Follows", "account.follows_you": "Follows you", + "account.media": "Media", "account.mention": "Mention @{name}", "account.mute": "Mute @{name}", "account.posts": "Posts", "account.report": "Report @{name}", "account.requested": "Awaiting approval", "account.unblock": "Unblock @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Unfollow", "account.unmute": "Unmute @{name}", "boost_modal.combo": "You can press {combo} to skip this next time", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 904c08cc9..3437bd9e9 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -1,17 +1,20 @@ { "account.block": "Bloki @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "This user is from another instance. This number may be larger.", "account.edit_profile": "Redakti la profilon", "account.follow": "Sekvi", "account.followers": "Sekvantoj", "account.follows": "Sekvatoj", "account.follows_you": "Sekvas vin", + "account.media": "Media", "account.mention": "Mencii @{name}", "account.mute": "Mute @{name}", "account.posts": "Mesaĝoj", "account.report": "Report @{name}", "account.requested": "Atendas aprobon", "account.unblock": "Malbloki @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Malsekvi", "account.unmute": "Unmute @{name}", "boost_modal.combo": "You can press {combo} to skip this next time", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 605c14a09..14b007a3e 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -1,17 +1,20 @@ { "account.block": "Bloquear", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "This user is from another instance. This number may be larger.", "account.edit_profile": "Editar perfil", "account.follow": "Seguir", "account.followers": "Seguidores", "account.follows": "Seguir", "account.follows_you": "Te sigue", + "account.media": "Media", "account.mention": "Mencionar", "account.mute": "Silenciar", "account.posts": "Publicaciones", "account.report": "Report @{name}", "account.requested": "Esperando aprobación", "account.unblock": "Desbloquear", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Dejar de seguir", "account.unmute": "Unmute @{name}", "boost_modal.combo": "You can press {combo} to skip this next time", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 72e938695..59266dcd9 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -1,17 +1,20 @@ { "account.block": "مسدودسازی @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "این کاربر عضو سرور متفاوتی است. شاید عدد واقعی بیشتر از این باشد.", "account.edit_profile": "ویرایش نمایه", "account.follow": "پی بگیرید", "account.followers": "پیگیران", "account.follows": "پی می‌گیرد", "account.follows_you": "پیگیر شماست", + "account.media": "Media", "account.mention": "نام‌بردن از @{name}", "account.mute": "بی‌صدا کردن @{name}", "account.posts": "نوشته‌ها", "account.report": "گزارش @{name}", "account.requested": "در انتظار پذیرش", "account.unblock": "رفع انسداد @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "پایان پیگیری", "account.unmute": "باصدا کردن @{name}", "boost_modal.combo": "دکمهٔ {combo} را بزنید تا دیگر این را نبینید", @@ -40,6 +43,8 @@ "confirmations.block.message": "آیا واقعاً می‌خواهید {name} را مسدود کنید؟", "confirmations.delete.confirm": "پاک کن", "confirmations.delete.message": "آیا واقعاً می‌خواهید این نوشته را پاک کنید؟", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "بی‌صدا کن", "confirmations.mute.message": "آیا واقعاً می‌خواهید {name} را بی‌صدا کنید؟", "emoji_button.activity": "فعالیت", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 42b1fbcb0..c544c955c 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -1,17 +1,20 @@ { "account.block": "Estä @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "This user is from another instance. This number may be larger.", "account.edit_profile": "Muokkaa", "account.follow": "Seuraa", "account.followers": "Seuraajia", "account.follows": "Seuraa", "account.follows_you": "Seuraa sinua", + "account.media": "Media", "account.mention": "Mainitse @{name}", "account.mute": "Mute @{name}", "account.posts": "Postit", "account.report": "Report @{name}", "account.requested": "Odottaa hyväksyntää", "account.unblock": "Salli @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Lopeta seuraaminen", "account.unmute": "Unmute @{name}", "boost_modal.combo": "You can press {combo} to skip this next time", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index c6665f43c..d3c292707 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -1,17 +1,20 @@ { "account.block": "Bloquer", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Ce compte est situé sur une autre instance. Les nombres peuvent être plus grands.", "account.edit_profile": "Modifier le profil", "account.follow": "Suivre", "account.followers": "Abonné⋅e⋅s", "account.follows": "Abonnements", "account.follows_you": "Vous suit", + "account.media": "Media", "account.mention": "Mentionner", "account.mute": "Masquer", "account.posts": "Statuts", "account.report": "Signaler", "account.requested": "Invitation envoyée", "account.unblock": "Débloquer", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Ne plus suivre", "account.unmute": "Ne plus masquer", "boost_modal.combo": "Vous pouvez appuyer sur {combo} pour pouvoir passer ceci, la prochaine fois", @@ -40,6 +43,8 @@ "confirmations.block.message": "Confirmez vous le blocage de {name} ?", "confirmations.delete.confirm": "Supprimer", "confirmations.delete.message": "Confirmez vous la suppression de ce pouet ?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Silencer", "confirmations.mute.message": "Confirmez vous la silenciation {name} ?", "emoji_button.activity": "Activités", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 8e4baa0c5..0a38065b5 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -1,17 +1,20 @@ { "account.block": "חסימת @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "משתמש זה מגיע מקהילה אחרת. המספר הזה עשוי להיות גדול יותר.", "account.edit_profile": "עריכת פרופיל", "account.follow": "מעקב", "account.followers": "עוקבים", "account.follows": "נעקבים", "account.follows_you": "במעקב אחריך", + "account.media": "Media", "account.mention": "אזכור של @{name}", "account.mute": "להשתיק את @{name}", "account.posts": "הודעות", "account.report": "לדווח על @{name}", "account.requested": "בהמתנה לאישור", "account.unblock": "הסרת חסימה מעל @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "הפסקת מעקב", "account.unmute": "הפסקת השתקת @{name}", "boost_modal.combo": "ניתן להקיש {combo} כדי לדלג בפעם הבאה", @@ -40,6 +43,8 @@ "confirmations.block.message": "לחסום את {name}?", "confirmations.delete.confirm": "למחוק", "confirmations.delete.message": "למחוק את ההודעה?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "להשתיק", "confirmations.mute.message": "להשתיק את {name}?", "emoji_button.activity": "פעילות", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index d263a73b9..6d4b43c00 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -1,17 +1,20 @@ { "account.block": "Blokiraj @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Ovaj korisnik je sa druge instance. Ovaj broj bi mogao biti veći.", "account.edit_profile": "Uredi profil", "account.follow": "Slijedi", "account.followers": "Sljedbenici", "account.follows": "Slijedi", "account.follows_you": "te slijedi", + "account.media": "Media", "account.mention": "Spomeni @{name}", "account.mute": "Utišaj @{name}", "account.posts": "Postovi", "account.report": "Prijavi @{name}", "account.requested": "Čeka pristanak", "account.unblock": "Deblokiraj @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Prestani slijediti", "account.unmute": "Poništi utišavanje @{name}", "boost_modal.combo": "Možeš pritisnuti {combo} kako bi ovo preskočio sljedeći put", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index c50501d24..ebe2d4171 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -1,17 +1,20 @@ { "account.block": "Blokkolás", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "This user is from another instance. This number may be larger.", "account.edit_profile": "Profil szerkesztése", "account.follow": "Követés", "account.followers": "Követők", "account.follows": "Követve", "account.follows_you": "Követnek téged", + "account.media": "Media", "account.mention": "Említés", "account.mute": "Mute @{name}", "account.posts": "Posts", "account.report": "Report @{name}", "account.requested": "Awaiting approval", "account.unblock": "Blokkolás levétele", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Követés abbahagyása", "account.unmute": "Unmute @{name}", "boost_modal.combo": "You can press {combo} to skip this next time", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index ca821a5d5..45eea622b 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -1,17 +1,20 @@ { "account.block": "Blokir @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Pengguna ini berasal dari server lain. Angka berikut mungkin lebih besar.", "account.edit_profile": "Ubah profil", "account.follow": "Ikuti", "account.followers": "Pengikut", "account.follows": "Mengikuti", "account.follows_you": "Mengikuti anda", + "account.media": "Media", "account.mention": "Balasan @{name}", "account.mute": "Bisukan @{name}", "account.posts": "Postingan", "account.report": "Laporkan @{name}", "account.requested": "Menunggu persetujuan", "account.unblock": "Hapus blokir @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Berhenti mengikuti", "account.unmute": "Berhenti membisukan @{name}", "boost_modal.combo": "Anda dapat menekan {combo} untuk melewati ini", @@ -40,6 +43,8 @@ "confirmations.block.message": "Apa anda yakin ingin memblokir {name}?", "confirmations.delete.confirm": "Hapus", "confirmations.delete.message": "Apa anda yakin akan menghapus status ini?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Bisukan", "confirmations.mute.message": "Apa anda yakin ingin membisukan {name}?", "emoji_button.activity": "Aktivitas", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index 34d38868f..f6791d180 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -1,17 +1,20 @@ { "account.block": "Blokusar @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Ca uzero esas de altra instaluro. Ca nombro forsan esas plu granda.", "account.edit_profile": "Modifikar profilo", "account.follow": "Sequar", "account.followers": "Sequanti", "account.follows": "Sequas", "account.follows_you": "Sequas tu", + "account.media": "Media", "account.mention": "Mencionar @{name}", "account.mute": "Celar @{name}", "account.posts": "Mesaji", "account.report": "Denuncar @{name}", "account.requested": "Vartante aprobo", "account.unblock": "Desblokusar @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Ne plus sequar", "account.unmute": "Ne plus celar @{name}", "boost_modal.combo": "Tu povas presar sur {combo} por omisar co en la venonta foyo", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 8b92ce86d..c09b705eb 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -1,17 +1,20 @@ { "account.block": "Blocca @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Questo utente si trova su un altro server. Questo numero potrebbe essere maggiore.", "account.edit_profile": "Modifica profilo", "account.follow": "Segui", "account.followers": "Seguaci", "account.follows": "Segue", "account.follows_you": "Ti segue", + "account.media": "Media", "account.mention": "Menziona @{name}", "account.mute": "Silenzia @{name}", "account.posts": "Posts", "account.report": "Segnala @{name}", "account.requested": "In attesa di approvazione", "account.unblock": "Sblocca @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Non seguire", "account.unmute": "Non silenziare @{name}", "boost_modal.combo": "Puoi premere {combo} per saltare questo passaggio la prossima volta", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 5f1ac2381..38745e20f 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -1,17 +1,20 @@ { "account.block": "ブロック", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "このユーザーは他のインスタンスに所属しているため、数字が正確で無い場合があります。", "account.edit_profile": "プロフィールを編集", "account.follow": "フォロー", "account.followers": "フォロワー", "account.follows": "フォロー", "account.follows_you": "フォローされています", + "account.media": "Media", "account.mention": "返信", "account.mute": "ミュート", "account.posts": "投稿", "account.report": "通報", "account.requested": "承認待ち", "account.unblock": "ブロック解除", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "フォロー解除", "account.unmute": "ミュート解除", "boost_modal.combo": "次からは{combo}を押せば、これをスキップできます。", @@ -40,6 +43,8 @@ "confirmations.block.message": "本当に{name}をブロックしますか?", "confirmations.delete.confirm": "削除", "confirmations.delete.message": "本当に削除しますか?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "ミュート", "confirmations.mute.message": "本当に{name}をミュートしますか?", "emoji_button.activity": "活動", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index e63f527c1..33e51a680 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -1,17 +1,20 @@ { "account.block": "Blokkeer @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Deze gebruiker zit op een andere server. Dit getal kan hoger zijn.", "account.edit_profile": "Profiel bewerken", "account.follow": "Volgen", "account.followers": "Volgers", "account.follows": "Volgt", "account.follows_you": "Volgt jou", + "account.media": "Media", "account.mention": "Vermeld @{name}", "account.mute": "Negeer @{name}", "account.posts": "Berichten", "account.report": "Rapporteer @{name}", "account.requested": "Wacht op goedkeuring", "account.unblock": "Deblokkeer @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Ontvolgen", "account.unmute": "Negeer @{name} niet meer", "boost_modal.combo": "Je kunt {combo} klikken om dit de volgende keer over te slaan", @@ -40,6 +43,8 @@ "confirmations.block.message": "Weet je zeker dat je {name} wilt blokkeren?", "confirmations.delete.confirm": "Verwijderen", "confirmations.delete.message": "Weet je zeker dat je deze toot wilt verwijderen?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Negeren", "confirmations.mute.message": "Weet je zeker dat je {name} wilt negeren?", "emoji_button.activity": "Activiteiten", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index d3fac55bd..1fddbaa21 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -1,17 +1,20 @@ { "account.block": "Blokkér @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Denne brukeren er fra en annen instans. Dette tallet kan være høyere.", "account.edit_profile": "Rediger profil", "account.follow": "Følg", "account.followers": "Følgere", "account.follows": "Følger", "account.follows_you": "Følger deg", + "account.media": "Media", "account.mention": "Nevn @{name}", "account.mute": "Demp @{name}", "account.posts": "Innlegg", "account.report": "Rapportér @{name}", "account.requested": "Venter på godkjennelse", "account.unblock": "Avblokker @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Avfølg", "account.unmute": "Avdemp @{name}", "boost_modal.combo": "You kan trykke {combo} for å hoppe over dette neste gang", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 8d4911187..506cf42e5 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -1,17 +1,20 @@ { "account.block": "Blocar", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Aqueste compte es sus una autra instància. Los nombres pòdon èsser mai grandes.", "account.edit_profile": "Modificar lo perfil", "account.follow": "Sègre", "account.followers": "Abonats", "account.follows": "Abonaments", "account.follows_you": "Vos sèc", + "account.media": "Media", "account.mention": "Mencionar", "account.mute": "Rescondre", "account.posts": "Estatuts", "account.report": "Senhalar", "account.requested": "Invitacion mandada", "account.unblock": "Desblocar", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Quitar de sègre", "account.unmute": "Quitar de rescondre", "boost_modal.combo": "Podètz butar {combo} per passar aquò lo còp que ven", @@ -40,6 +43,8 @@ "confirmations.block.message": "Sètz segur de voler blocar {name}?", "confirmations.delete.confirm": "Suprimir", "confirmations.delete.message": "Sètz segur de voler suprimir l’estatut ?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Metre en silenci", "confirmations.mute.message": "Sètz segur de voler metre en silenci {name}?", "emoji_button.activity": "Activitat", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 2a18dff8f..f51d2ee58 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -1,17 +1,20 @@ { "account.block": "Blokuj @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Ten użytkownik pochodzi z innej instancji. Ta liczba może być większa.", "account.edit_profile": "Edytuj profil", "account.follow": "Obserwuj", "account.followers": "Obserwujący", "account.follows": "Obserwacje", "account.follows_you": "Obserwują cię", + "account.media": "Media", "account.mention": "Wspomnij o @{name}", "account.mute": "Wycisz @{name}", "account.posts": "Posty", "account.report": "Zgłoś @{name}", "account.requested": "Oczekująca prośba", "account.unblock": "Odblokuj @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Przestań obserwować", "account.unmute": "Cofnij wyciszenie @{name}", "boost_modal.combo": "Naciśnij {combo}, aby pominąć to następnym razem", @@ -40,6 +43,8 @@ "confirmations.block.message": "Czy na pewno chcesz zablokować {name}?", "confirmations.delete.confirm": "Usuń", "confirmations.delete.message": "Czy na pewno chcesz usunąć ten status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Wycisz", "confirmations.mute.message": "Czy na pewno chcesz wyciszyć {name}?", "emoji_button.activity": "Aktywność", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 57b31733d..c5af75d9c 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -1,17 +1,20 @@ { "account.block": "Bloquear @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Essa conta está localizado em outra instância. Os nomes podem ser maiores.", "account.edit_profile": "Editar perfil", "account.follow": "Seguir", "account.followers": "Seguidores", "account.follows": "Segue", "account.follows_you": "É teu seguidor", + "account.media": "Media", "account.mention": "Mencionar @{name}", "account.mute": "Silenciar @{name}", "account.posts": "Posts", "account.report": "Denunciar @{name}", "account.requested": "A aguardar aprovação", "account.unblock": "Não bloquear @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Deixar de seguir", "account.unmute": "Não silenciar @{name}", "boost_modal.combo": "Pode clicar {combo} para não voltar a ver", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json index 57b31733d..c5af75d9c 100644 --- a/app/javascript/mastodon/locales/pt.json +++ b/app/javascript/mastodon/locales/pt.json @@ -1,17 +1,20 @@ { "account.block": "Bloquear @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Essa conta está localizado em outra instância. Os nomes podem ser maiores.", "account.edit_profile": "Editar perfil", "account.follow": "Seguir", "account.followers": "Seguidores", "account.follows": "Segue", "account.follows_you": "É teu seguidor", + "account.media": "Media", "account.mention": "Mencionar @{name}", "account.mute": "Silenciar @{name}", "account.posts": "Posts", "account.report": "Denunciar @{name}", "account.requested": "A aguardar aprovação", "account.unblock": "Não bloquear @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Deixar de seguir", "account.unmute": "Não silenciar @{name}", "boost_modal.combo": "Pode clicar {combo} para não voltar a ver", @@ -40,6 +43,8 @@ "confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.delete.confirm": "Delete", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Mute", "confirmations.mute.message": "Are you sure you want to mute {name}?", "emoji_button.activity": "Activity", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 83d74c619..ba4642ab9 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -1,17 +1,20 @@ { "account.block": "Блокировать", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Это пользователь с другого узла. Число может быть больше.", "account.edit_profile": "Изменить профиль", "account.follow": "Подписаться", "account.followers": "Подписаны", "account.follows": "Подписки", "account.follows_you": "Подписан(а) на Вас", + "account.media": "Media", "account.mention": "Упомянуть", "account.mute": "Заглушить", "account.posts": "Посты", "account.report": "Пожаловаться", "account.requested": "Ожидает подтверждения", "account.unblock": "Разблокировать", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Отписаться", "account.unmute": "Снять глушение", "boost_modal.combo": "Нажмите {combo}, чтобы пропустить это в следующий раз", @@ -40,6 +43,8 @@ "confirmations.block.message": "Вы уверены, что хотите заблокировать {name}?", "confirmations.delete.confirm": "Удалить", "confirmations.delete.message": "Вы уверены, что хотите удалить этот статус?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Заглушить", "confirmations.mute.message": "Вы уверены, что хотите заглушить {name}?", "emoji_button.activity": "Занятия", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index ef9c43d0b..ebfa95b84 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -1,17 +1,20 @@ { "account.block": "Engelle @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Bu kullanıcının hesabı farklı sunucuda bulunduğu için bu sayı daha fazla olabilir.", "account.edit_profile": "Profili düzenle", "account.follow": "Takip et", "account.followers": "Takipçiler", "account.follows": "Takip ettikleri", "account.follows_you": "Seni takip ediyor", + "account.media": "Media", "account.mention": "Bahset @{name}", "account.mute": "Sustur @{name}", "account.posts": "Gönderiler", "account.report": "Rapor et @{name}", "account.requested": "Onay bekleniyor", "account.unblock": "Engeli kaldır @{name}", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Takipten vazgeç", "account.unmute": "Sesi aç @{name}", "boost_modal.combo": "Bir dahaki sefere {combo} tuşuna basabilirsiniz", @@ -40,6 +43,8 @@ "confirmations.block.message": "{name} kullanıcısını engellemek istiyor musunuz?", "confirmations.delete.confirm": "Sil", "confirmations.delete.message": "Bu gönderiyi silmek istiyor musunuz?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Sessize al", "confirmations.mute.message": "{name} kullanıcısını sessize almak istiyor musunuz?", "emoji_button.activity": "Aktivite", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 99df3b4f4..cd2fa6b11 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -1,17 +1,20 @@ { "account.block": "Заблокувати", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "Це користувач з іншої інстанції. Число може бути більше.", "account.edit_profile": "Налаштування профілю", "account.follow": "Підписатися", "account.followers": "Підписники", "account.follows": "Підписки", "account.follows_you": "Підписаний(-а) на Вас", + "account.media": "Media", "account.mention": "Згадати", "account.mute": "Заглушити", "account.posts": "Пости", "account.report": "Поскаржитися", "account.requested": "Очікує підтвердження", "account.unblock": "Розблокувати", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "Відписатися", "account.unmute": "Зняти глушення", "boost_modal.combo": "Ви можете натиснути {combo}, щоб пропустити це наступного разу", @@ -40,6 +43,8 @@ "confirmations.block.message": "Ви впевнені, що хочете заблокувати {name}?", "confirmations.delete.confirm": "Видалити", "confirmations.delete.message": "Ви впевнені, що хочете видалити цей допис?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Заглушить", "confirmations.mute.message": "Ви впевнені, що хочете заглушити {name}?", "emoji_button.activity": "Заняття", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index fed311cf7..45eb663a0 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -1,17 +1,20 @@ { "account.block": "屏蔽 @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "由于这个账户处于另一个服务站上,实际数字会比这个更多。", "account.edit_profile": "修改个人资料", "account.follow": "关注", "account.followers": "关注者", "account.follows": "正关注", "account.follows_you": "关注你", + "account.media": "Media", "account.mention": "提及 @{name}", "account.mute": "将 @{name} 静音", "account.posts": "嘟文", "account.report": "举报 @{name}", "account.requested": "等候审批", "account.unblock": "解除对 @{name} 的屏蔽", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "取消关注", "account.unmute": "取消 @{name} 的静音", "boost_modal.combo": "如你想在下次路过时显示,请按{combo},", @@ -40,6 +43,8 @@ "confirmations.block.message": "想好了,真的要屏蔽 {name}?", "confirmations.delete.confirm": "删除", "confirmations.delete.message": "想好了,真的要删除这条嘟文?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "静音", "confirmations.mute.message": "想好了,真的要静音 {name}?", "emoji_button.activity": "活动", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index f3637bf74..23611ae97 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -1,17 +1,20 @@ { "account.block": "封鎖 @{name}", + "account.block_domain": "Hide everything from {domain}", "account.disclaimer": "由於這個用戶在另一個服務站,實際數字會比這個更多。", "account.edit_profile": "修改個人資料", "account.follow": "關注", "account.followers": "關注的人", "account.follows": "正在關注", "account.follows_you": "關注你", + "account.media": "Media", "account.mention": "提及 @{name}", "account.mute": "將 @{name} 靜音", "account.posts": "文章", "account.report": "舉報 @{name}", "account.requested": "等候審批", "account.unblock": "解除對 @{name} 的封鎖", + "account.unblock_domain": "Unhide {domain}", "account.unfollow": "取消關注", "account.unmute": "取消 @{name} 的靜音", "boost_modal.combo": "如你想在下次路過這顯示,請按{combo},", @@ -40,6 +43,8 @@ "confirmations.block.message": "你確定要封鎖{name}嗎?", "confirmations.delete.confirm": "刪除", "confirmations.delete.message": "你確定要刪除{name}嗎?", + "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "靜音", "confirmations.mute.message": "你確定要將{name}靜音嗎?", "emoji_button.activity": "活動", diff --git a/app/javascript/mastodon/reducers/relationships.js b/app/javascript/mastodon/reducers/relationships.js index c65c48b43..f25c0b55a 100644 --- a/app/javascript/mastodon/reducers/relationships.js +++ b/app/javascript/mastodon/reducers/relationships.js @@ -7,6 +7,10 @@ import { ACCOUNT_UNMUTE_SUCCESS, RELATIONSHIPS_FETCH_SUCCESS } from '../actions/accounts'; +import { + DOMAIN_BLOCK_SUCCESS, + DOMAIN_UNBLOCK_SUCCESS +} from '../actions/domain_blocks'; import Immutable from 'immutable'; const normalizeRelationship = (state, relationship) => state.set(relationship.id, Immutable.fromJS(relationship)); @@ -32,6 +36,10 @@ export default function relationships(state = initialState, action) { return normalizeRelationship(state, action.relationship); case RELATIONSHIPS_FETCH_SUCCESS: return normalizeRelationships(state, action.relationships); + case DOMAIN_BLOCK_SUCCESS: + return state.setIn([action.accountId, 'domain_blocking'], true); + case DOMAIN_UNBLOCK_SUCCESS: + return state.setIn([action.accountId, 'domain_blocking'], false); default: return state; } diff --git a/app/models/account_domain_block.rb b/app/models/account_domain_block.rb index 9241d9720..bdd64c01a 100644 --- a/app/models/account_domain_block.rb +++ b/app/models/account_domain_block.rb @@ -14,6 +14,7 @@ class AccountDomainBlock < ApplicationRecord include Paginable belongs_to :account, required: true + validates :domain, presence: true, uniqueness: { scope: :account_id } after_create :remove_blocking_cache after_destroy :remove_blocking_cache diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index c8006bd0b..0ef7512e2 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -23,6 +23,12 @@ module AccountInteractions def requested_map(target_account_ids, account_id) follow_mapping(FollowRequest.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) end + + def domain_blocking_map(target_account_ids, account_id) + accounts_map = Account.where(id: target_account_ids).select('id, domain').map { |a| [a.id, a.domain] }.to_h + blocked_domains = AccountDomainBlock.where(account_id: account_id, domain: accounts_map.values).pluck(:domain) + accounts_map.map { |id, domain| [id, blocked_domains.include?(domain)] }.to_h + end end included do diff --git a/app/models/status.rb b/app/models/status.rb index 70021eb65..80f33a7c7 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -67,7 +67,8 @@ class Status < ApplicationRecord scope :local_only, -> { left_outer_joins(:account).where(accounts: { domain: nil }) } scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: false }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: true }) } - scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids, accounts: { domain: account.excluded_from_timeline_domains }) } + scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) } + scope :not_domain_blocked_by_account, ->(account) { left_outer_joins(:account).where.not(accounts: { domain: account.excluded_from_timeline_domains }) } cache_associated :account, :application, :media_attachments, :tags, :stream_entry, mentions: :account, reblog: [:account, :application, :stream_entry, :tags, :media_attachments, mentions: :account], thread: :account @@ -152,13 +153,13 @@ class Status < ApplicationRecord def as_public_timeline(account = nil, local_only = false) query = timeline_scope(local_only).without_replies - apply_timeline_filters(query, account) + apply_timeline_filters(query, account, local_only) end def as_tag_timeline(tag, account = nil, local_only = false) query = timeline_scope(local_only).tagged_with(tag) - apply_timeline_filters(query, account) + apply_timeline_filters(query, account, local_only) end def as_outbox_timeline(account) @@ -222,16 +223,17 @@ class Status < ApplicationRecord .without_reblogs end - def apply_timeline_filters(query, account) + def apply_timeline_filters(query, account, local_only) if account.nil? filter_timeline_default(query) else - filter_timeline_for_account(query, account) + filter_timeline_for_account(query, account, local_only) end end - def filter_timeline_for_account(query, account) + def filter_timeline_for_account(query, account, local_only) query = query.not_excluded_by_account(account) + query = query.not_domain_blocked_by_account(account) unless local_only query = query.in_allowed_languages(account) if account.allowed_languages.present? query.merge(account_silencing_filter(account)) end diff --git a/app/services/block_domain_from_account_service.rb b/app/services/block_domain_from_account_service.rb new file mode 100644 index 000000000..cae7abcbd --- /dev/null +++ b/app/services/block_domain_from_account_service.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class BlockDomainFromAccountService < BaseService + def call(account, domain) + account.block_domain!(domain) + account.passive_relationships.where(account: Account.where(domain: domain)).delete_all + end +end diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index 150ffe6b2..ce22b6505 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -37,15 +37,15 @@ class NotifyService < BaseService end def blocked? - blocked = @recipient.suspended? # Skip if the recipient account is suspended anyway - blocked ||= @recipient.id == @notification.from_account.id # Skip for interactions with self - blocked ||= @recipient.domain_blocking?(@notification.from_account.domain) # Skip for domain blocked accounts - blocked ||= @recipient.blocking?(@notification.from_account) # Skip for blocked accounts - blocked ||= (@notification.from_account.silenced? && !@recipient.following?(@notification.from_account)) # Hellban - blocked ||= (@recipient.user.settings.interactions['must_be_follower'] && !@notification.from_account.following?(@recipient)) # Options - blocked ||= (@recipient.user.settings.interactions['must_be_following'] && !@recipient.following?(@notification.from_account)) # Options + blocked = @recipient.suspended? # Skip if the recipient account is suspended anyway + blocked ||= @recipient.id == @notification.from_account.id # Skip for interactions with self + blocked ||= @recipient.domain_blocking?(@notification.from_account.domain) && !@recipient.following?(@notification.from_account) # Skip for domain blocked accounts + blocked ||= @recipient.blocking?(@notification.from_account) # Skip for blocked accounts + blocked ||= (@notification.from_account.silenced? && !@recipient.following?(@notification.from_account)) # Hellban + blocked ||= (@recipient.user.settings.interactions['must_be_follower'] && !@notification.from_account.following?(@recipient)) # Options + blocked ||= (@recipient.user.settings.interactions['must_be_following'] && !@recipient.following?(@notification.from_account)) # Options blocked ||= conversation_muted? - blocked ||= send("blocked_#{@notification.type}?") # Type-dependent filters + blocked ||= send("blocked_#{@notification.type}?") # Type-dependent filters blocked end diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb index bc8361510..e9c01103d 100644 --- a/app/services/process_interaction_service.rb +++ b/app/services/process_interaction_service.rb @@ -21,9 +21,9 @@ class ProcessInteractionService < BaseService case verb(xml) when :follow - follow!(account, target_account) unless target_account.locked? || target_account.blocking?(account) + follow!(account, target_account) unless target_account.locked? || target_account.blocking?(account) || target_account.domain_blocking?(account.domain) when :request_friend - follow_request!(account, target_account) unless !target_account.locked? || target_account.blocking?(account) + follow_request!(account, target_account) unless !target_account.locked? || target_account.blocking?(account) || target_account.domain_blocking?(account.domain) when :authorize authorize_follow_request!(account, target_account) when :reject diff --git a/app/services/send_interaction_service.rb b/app/services/send_interaction_service.rb index 99113eeca..504f41c72 100644 --- a/app/services/send_interaction_service.rb +++ b/app/services/send_interaction_service.rb @@ -6,12 +6,22 @@ class SendInteractionService < BaseService # @param [Account] source_account # @param [Account] target_account def call(xml, source_account, target_account) - envelope = salmon.pack(xml, source_account.keypair) - salmon.post(target_account.salmon_url, envelope) + @xml = xml + @source_account = source_account + @target_account = target_account + + return if block_notification? + + envelope = salmon.pack(@xml, @source_account.keypair) + salmon.post(@target_account.salmon_url, envelope) end private + def block_notification? + DomainBlock.blocked?(@target_account.domain) + end + def salmon @salmon ||= OStatus2::Salmon.new end diff --git a/app/views/api/v1/accounts/relationship.rabl b/app/views/api/v1/accounts/relationship.rabl index d6f1dd48a..4f7763d9d 100644 --- a/app/views/api/v1/accounts/relationship.rabl +++ b/app/views/api/v1/accounts/relationship.rabl @@ -1,8 +1,9 @@ object @account attribute :id -node(:following) { |account| @following[account.id] || false } -node(:followed_by) { |account| @followed_by[account.id] || false } -node(:blocking) { |account| @blocking[account.id] || false } -node(:muting) { |account| @muting[account.id] || false } -node(:requested) { |account| @requested[account.id] || false } +node(:following) { |account| @following[account.id] || false } +node(:followed_by) { |account| @followed_by[account.id] || false } +node(:blocking) { |account| @blocking[account.id] || false } +node(:muting) { |account| @muting[account.id] || false } +node(:requested) { |account| @requested[account.id] || false } +node(:domain_blocking) { |account| @domain_blocking[account.id] || false } diff --git a/spec/services/block_domain_from_account_service_spec.rb b/spec/services/block_domain_from_account_service_spec.rb new file mode 100644 index 000000000..e7ee34372 --- /dev/null +++ b/spec/services/block_domain_from_account_service_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +RSpec.describe BlockDomainFromAccountService do + let!(:wolf) { Fabricate(:account, username: 'wolf', domain: 'evil.org') } + let!(:alice) { Fabricate(:account, username: 'alice') } + + subject { BlockDomainFromAccountService.new } + + it 'creates domain block' do + subject.call(alice, 'evil.org') + expect(alice.domain_blocking?('evil.org')).to be true + end + + it 'purge followers from blocked domain' do + wolf.follow!(alice) + subject.call(alice, 'evil.org') + expect(wolf.following?(alice)).to be false + end +end diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index 29bd741aa..7a66bd0fe 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -22,6 +22,12 @@ RSpec.describe NotifyService do is_expected.to_not change(Notification, :count) end + it 'does still notify when sender\'s domain is blocked but sender is followed' do + recipient.block_domain!(sender.domain) + recipient.follow!(sender) + is_expected.to change(Notification, :count) + end + it 'does not notify when sender is silenced and not followed' do sender.update(silenced: true) is_expected.to_not change(Notification, :count)