summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/api/v1/accounts_controller.rb35
-rw-r--r--app/controllers/api/v1/domain_blocks_controller.rb2
-rw-r--r--app/javascript/mastodon/actions/domain_blocks.js117
-rw-r--r--app/javascript/mastodon/features/account/components/action_bar.js15
-rw-r--r--app/javascript/mastodon/features/account_timeline/components/header.js22
-rw-r--r--app/javascript/mastodon/features/account_timeline/containers/header_container.js16
-rw-r--r--app/javascript/mastodon/locales/ar.json5
-rw-r--r--app/javascript/mastodon/locales/bg.json5
-rw-r--r--app/javascript/mastodon/locales/ca.json5
-rw-r--r--app/javascript/mastodon/locales/de.json5
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json25
-rw-r--r--app/javascript/mastodon/locales/en.json5
-rw-r--r--app/javascript/mastodon/locales/eo.json5
-rw-r--r--app/javascript/mastodon/locales/es.json5
-rw-r--r--app/javascript/mastodon/locales/fa.json5
-rw-r--r--app/javascript/mastodon/locales/fi.json5
-rw-r--r--app/javascript/mastodon/locales/fr.json5
-rw-r--r--app/javascript/mastodon/locales/he.json5
-rw-r--r--app/javascript/mastodon/locales/hr.json5
-rw-r--r--app/javascript/mastodon/locales/hu.json5
-rw-r--r--app/javascript/mastodon/locales/id.json5
-rw-r--r--app/javascript/mastodon/locales/io.json5
-rw-r--r--app/javascript/mastodon/locales/it.json5
-rw-r--r--app/javascript/mastodon/locales/ja.json5
-rw-r--r--app/javascript/mastodon/locales/nl.json5
-rw-r--r--app/javascript/mastodon/locales/no.json5
-rw-r--r--app/javascript/mastodon/locales/oc.json5
-rw-r--r--app/javascript/mastodon/locales/pl.json5
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json5
-rw-r--r--app/javascript/mastodon/locales/pt.json5
-rw-r--r--app/javascript/mastodon/locales/ru.json5
-rw-r--r--app/javascript/mastodon/locales/tr.json5
-rw-r--r--app/javascript/mastodon/locales/uk.json5
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json5
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json5
-rw-r--r--app/javascript/mastodon/reducers/relationships.js8
-rw-r--r--app/models/account_domain_block.rb1
-rw-r--r--app/models/concerns/account_interactions.rb6
-rw-r--r--app/models/status.rb14
-rw-r--r--app/services/block_domain_from_account_service.rb8
-rw-r--r--app/services/notify_service.rb16
-rw-r--r--app/services/process_interaction_service.rb4
-rw-r--r--app/services/send_interaction_service.rb14
-rw-r--r--app/views/api/v1/accounts/relationship.rabl11
-rw-r--r--spec/services/block_domain_from_account_service_spec.rb19
-rw-r--r--spec/services/notify_service_spec.rb6
46 files changed, 436 insertions, 43 deletions
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 5724dbaea4f..12c7dd2b08c 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 e14547911c7..f223dd16ee5 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 00000000000..c884981176b
--- /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 44ed8af7d18..1997bf7b732 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 = <abbr title={intl.formatMessage(messages.disclaimer)}>*</abbr>;
+
+ 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 d7226d9b20b..f1a0e8d775b 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}
/>
</div>
);
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 50999d2e0e6..0964efdcfee 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: <FormattedMessage id='confirmations.domain_block.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.' values={{ domain: <strong>{domain}</strong> }} />,
+ 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 e30b7e84aec..2a9d00460a6 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": "هذا المستخدم Ù…Ù