diff --git a/app/assets/javascripts/components/actions/accounts.jsx b/app/assets/javascripts/components/actions/accounts.jsx
index c4aa2d80c7..eeec405d10 100644
--- a/app/assets/javascripts/components/actions/accounts.jsx
+++ b/app/assets/javascripts/components/actions/accounts.jsx
@@ -15,6 +15,14 @@ export const ACCOUNT_UNFOLLOW_REQUEST = 'ACCOUNT_UNFOLLOW_REQUEST';
export const ACCOUNT_UNFOLLOW_SUCCESS = 'ACCOUNT_UNFOLLOW_SUCCESS';
export const ACCOUNT_UNFOLLOW_FAIL = 'ACCOUNT_UNFOLLOW_FAIL';
+export const ACCOUNT_BLOCK_REQUEST = 'ACCOUNT_BLOCK_REQUEST';
+export const ACCOUNT_BLOCK_SUCCESS = 'ACCOUNT_BLOCK_SUCCESS';
+export const ACCOUNT_BLOCK_FAIL = 'ACCOUNT_BLOCK_FAIL';
+
+export const ACCOUNT_UNBLOCK_REQUEST = 'ACCOUNT_UNBLOCK_REQUEST';
+export const ACCOUNT_UNBLOCK_SUCCESS = 'ACCOUNT_UNBLOCK_SUCCESS';
+export const ACCOUNT_UNBLOCK_FAIL = 'ACCOUNT_UNBLOCK_FAIL';
+
export const ACCOUNT_TIMELINE_FETCH_REQUEST = 'ACCOUNT_TIMELINE_FETCH_REQUEST';
export const ACCOUNT_TIMELINE_FETCH_SUCCESS = 'ACCOUNT_TIMELINE_FETCH_SUCCESS';
export const ACCOUNT_TIMELINE_FETCH_FAIL = 'ACCOUNT_TIMELINE_FETCH_FAIL';
@@ -204,3 +212,69 @@ export function expandAccountTimelineFail(id, error) {
error: error
};
};
+
+export function blockAccount(id) {
+ return (dispatch, getState) => {
+ dispatch(blockAccountRequest(id));
+
+ api(getState).post(`/api/v1/accounts/${id}/block`).then(response => {
+ dispatch(blockAccountSuccess(response.data));
+ }).catch(error => {
+ dispatch(blockAccountFail(id, error));
+ });
+ };
+};
+
+export function unblockAccount(id) {
+ return (dispatch, getState) => {
+ dispatch(unblockAccountRequest(id));
+
+ api(getState).post(`/api/v1/accounts/${id}/unblock`).then(response => {
+ dispatch(unblockAccountSuccess(response.data));
+ }).catch(error => {
+ dispatch(unblockAccountFail(id, error));
+ });
+ };
+};
+
+export function blockAccountRequest(id) {
+ return {
+ type: ACCOUNT_BLOCK_REQUEST,
+ id: id
+ };
+};
+
+export function blockAccountSuccess(relationship) {
+ return {
+ type: ACCOUNT_BLOCK_SUCCESS,
+ relationship: relationship
+ };
+};
+
+export function blockAccountFail(error) {
+ return {
+ type: ACCOUNT_BLOCK_FAIL,
+ error: error
+ };
+};
+
+export function unblockAccountRequest(id) {
+ return {
+ type: ACCOUNT_UNBLOCK_REQUEST,
+ id: id
+ };
+};
+
+export function unblockAccountSuccess(relationship) {
+ return {
+ type: ACCOUNT_UNBLOCK_SUCCESS,
+ relationship: relationship
+ };
+};
+
+export function unblockAccountFail(error) {
+ return {
+ type: ACCOUNT_UNBLOCK_FAIL,
+ error: error
+ };
+};
diff --git a/app/assets/javascripts/components/components/status_action_bar.jsx b/app/assets/javascripts/components/components/status_action_bar.jsx
index 76f0ac5f19..3e826d68a0 100644
--- a/app/assets/javascripts/components/components/status_action_bar.jsx
+++ b/app/assets/javascripts/components/components/status_action_bar.jsx
@@ -41,6 +41,8 @@ const StatusActionBar = React.createClass({
Delete
);
+ } else {
+ menu = ;
}
return (
diff --git a/app/assets/javascripts/components/features/account/components/action_bar.jsx b/app/assets/javascripts/components/features/account/components/action_bar.jsx
index 309471dd22..aadf168b2b 100644
--- a/app/assets/javascripts/components/features/account/components/action_bar.jsx
+++ b/app/assets/javascripts/components/features/account/components/action_bar.jsx
@@ -7,7 +7,8 @@ const ActionBar = React.createClass({
propTypes: {
account: ImmutablePropTypes.map.isRequired,
me: React.PropTypes.number.isRequired,
- onFollow: React.PropTypes.func.isRequired
+ onFollow: React.PropTypes.func.isRequired,
+ onBlock: React.PropTypes.func.isRequired
},
mixins: [PureRenderMixin],
@@ -16,25 +17,46 @@ const ActionBar = React.createClass({
const { account, me } = this.props;
let infoText = '';
+ let follow = '';
let buttonText = '';
+ let block = '';
+ let disabled = false;
if (account.get('id') === me) {
buttonText = 'This is you!';
+ disabled = true;
} else {
- if (account.getIn(['relationship', 'following'])) {
- buttonText = 'Unfollow';
+ let blockText = '';
+
+ if (account.getIn(['relationship', 'blocking'])) {
+ buttonText = 'Blocked';
+ disabled = true;
+ blockText = 'Unblock';
} else {
- buttonText = 'Follow';
+ if (account.getIn(['relationship', 'following'])) {
+ buttonText = 'Unfollow';
+ } else {
+ buttonText = 'Follow';
+ }
+
+ if (account.getIn(['relationship', 'followed_by'])) {
+ infoText = 'Follows you!';
+ }
+
+ blockText = 'Block';
}
- if (account.getIn(['relationship', 'followed_by'])) {
- infoText = 'Follows you!';
- }
+ block = ;
+ }
+
+ if (!account.getIn(['relationship', 'blocking'])) {
+ follow = ;
}
return (
- {infoText}
+ {follow} {block}
+ {infoText}
);
},
diff --git a/app/assets/javascripts/components/features/account/index.jsx b/app/assets/javascripts/components/features/account/index.jsx
index 40c06c545b..c2389af2ea 100644
--- a/app/assets/javascripts/components/features/account/index.jsx
+++ b/app/assets/javascripts/components/features/account/index.jsx
@@ -5,6 +5,8 @@ import {
fetchAccount,
followAccount,
unfollowAccount,
+ blockAccount,
+ unblockAccount,
fetchAccountTimeline,
expandAccountTimeline
} from '../../actions/accounts';
@@ -66,6 +68,14 @@ const Account = React.createClass({
}
},
+ handleBlock () {
+ if (this.props.account.getIn(['relationship', 'blocking'])) {
+ this.props.dispatch(unblockAccount(this.props.account.get('id')));
+ } else {
+ this.props.dispatch(blockAccount(this.props.account.get('id')));
+ }
+ },
+
handleReply (status) {
this.props.dispatch(replyCompose(status));
},
@@ -104,7 +114,7 @@ const Account = React.createClass({
return (
);
diff --git a/app/assets/javascripts/components/reducers/timelines.jsx b/app/assets/javascripts/components/reducers/timelines.jsx
index ec42b7825b..3926831509 100644
--- a/app/assets/javascripts/components/reducers/timelines.jsx
+++ b/app/assets/javascripts/components/reducers/timelines.jsx
@@ -15,6 +15,8 @@ import {
ACCOUNT_FETCH_SUCCESS,
ACCOUNT_FOLLOW_SUCCESS,
ACCOUNT_UNFOLLOW_SUCCESS,
+ ACCOUNT_BLOCK_SUCCESS,
+ ACCOUNT_UNBLOCK_SUCCESS,
ACCOUNT_TIMELINE_FETCH_SUCCESS,
ACCOUNT_TIMELINE_EXPAND_SUCCESS
} from '../actions/accounts';
@@ -231,6 +233,8 @@ export default function timelines(state = initialState, action) {
return normalizeAccount(state, Immutable.fromJS(action.account), Immutable.fromJS(action.relationship));
case ACCOUNT_FOLLOW_SUCCESS:
case ACCOUNT_UNFOLLOW_SUCCESS:
+ case ACCOUNT_UNBLOCK_SUCCESS:
+ case ACCOUNT_BLOCK_SUCCESS:
return normalizeRelationship(state, Immutable.fromJS(action.relationship));
case STATUS_FETCH_SUCCESS:
return normalizeContext(state, Immutable.fromJS(action.status), Immutable.fromJS(action.context.ancestors), Immutable.fromJS(action.context.descendants));
diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss
index 7c111e04af..155517362c 100644
--- a/app/assets/stylesheets/components.scss
+++ b/app/assets/stylesheets/components.scss
@@ -170,7 +170,6 @@
.dropdown--active .dropdown__content {
display: block;
z-index: 9999;
- box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);
&:before {
content: "";
@@ -187,20 +186,11 @@
ul {
list-style: none;
- }
-
- li {
- &:first-child a {
- border-radius: 4px 4px 0 0;
- }
-
- &:last-child a {
- border-radius: 0 0 4px 4px;
- }
-
- &:first-child:last-child a {
- border-radius: 4px;
- }
+ background: #d9e1e8;
+ padding: 4px 0;
+ border-radius: 4px;
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);
+ min-width: 100px;
}
a {
diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb
index 3d0bc718c8..98f08d32b8 100644
--- a/app/services/favourite_service.rb
+++ b/app/services/favourite_service.rb
@@ -8,7 +8,7 @@ class FavouriteService < BaseService
account.ping!(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url])
if status.local?
- NotificationMailer.favourite(status, account).deliver_later
+ NotificationMailer.favourite(status, account).deliver_later unless status.account.blocking?(account)
else
NotificationWorker.perform_async(favourite.stream_entry.id, status.account_id)
end
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 6dd85dd7dd..f44d533980 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -10,7 +10,7 @@ class FollowService < BaseService
follow = source_account.follow!(target_account)
if target_account.local?
- NotificationMailer.follow(target_account, source_account).deliver_later
+ NotificationMailer.follow(target_account, source_account).deliver_later unless target_account.blocking?(source_account)
else
subscribe_service.call(target_account)
NotificationWorker.perform_async(follow.stream_entry.id, target_account.id)
diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb
index 1ea79835bc..9585b15ddc 100644
--- a/app/services/process_feed_service.rb
+++ b/app/services/process_feed_service.rb
@@ -69,7 +69,7 @@ class ProcessFeedService < BaseService
unless mentioned_account.nil?
mentioned_account.mentions.where(status: status).first_or_create(status: status)
- NotificationMailer.mention(mentioned_account, status).deliver_later
+ NotificationMailer.mention(mentioned_account, status).deliver_later unless mentioned_account.blocking?(status.account)
end
else
# What to do about remote user?
@@ -114,7 +114,7 @@ class ProcessFeedService < BaseService
if !status.reblog.nil?
status.save!
- NotificationMailer.reblog(status.reblog, status.account).deliver_later if status.reblog.local?
+ NotificationMailer.reblog(status.reblog, status.account).deliver_later if status.reblog.local? && !status.reblog.account.blocking?(status.account)
end
end
diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb
index 96dae30da3..31c7c46a53 100644
--- a/app/services/process_interaction_service.rb
+++ b/app/services/process_interaction_service.rb
@@ -58,7 +58,7 @@ class ProcessInteractionService < BaseService
def follow!(account, target_account)
account.follow!(target_account)
- NotificationMailer.follow(target_account, account).deliver_later
+ NotificationMailer.follow(target_account, account).deliver_later unless target_account.blocking?(account)
end
def unfollow!(account, target_account)
@@ -78,7 +78,7 @@ class ProcessInteractionService < BaseService
def favourite!(xml, from_account)
current_status = status(xml)
current_status.favourites.where(account: from_account).first_or_create!(account: from_account)
- NotificationMailer.favourite(current_status, from_account).deliver_later
+ NotificationMailer.favourite(current_status, from_account).deliver_later unless current_status.account.blocking?(from_account)
end
def add_post!(body, account)
diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb
index 2d09fc2cdf..8baa03d070 100644
--- a/app/services/process_mentions_service.rb
+++ b/app/services/process_mentions_service.rb
@@ -27,7 +27,7 @@ class ProcessMentionsService < BaseService
mentioned_account = mention.account
if mentioned_account.local?
- NotificationMailer.mention(mentioned_account, status).deliver_later
+ NotificationMailer.mention(mentioned_account, status).deliver_later unless mentioned_account.blocking?(status.account)
else
NotificationWorker.perform_async(status.stream_entry.id, mentioned_account.id)
end
diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb
index f149477c77..56c59cb18e 100644
--- a/app/services/reblog_service.rb
+++ b/app/services/reblog_service.rb
@@ -9,7 +9,7 @@ class ReblogService < BaseService
account.ping!(account_url(account, format: 'atom'), [Rails.configuration.x.hub_url])
if reblogged_status.local?
- NotificationMailer.reblog(reblogged_status, account).deliver_later
+ NotificationMailer.reblog(reblogged_status, account).deliver_later unless reblogged_status.account.blocking?(account)
else
NotificationWorker.perform_async(reblog.stream_entry.id, reblogged_status.account_id)
end