add option to set mutes that apply only to timelines

master
multiple creatures 2019-12-21 12:08:49 -06:00
parent 82f98a770b
commit b8f7ccf227
11 changed files with 57 additions and 18 deletions

View File

@ -42,7 +42,7 @@ class Api::V1::AccountsController < Api::BaseController
end
def mute
MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications))
MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications), timelines_only: truthy_param?(:timelines_only))
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships
end

View File

@ -264,11 +264,11 @@ export function unblockAccountFail(error) {
};
export function muteAccount(id, notifications) {
export function muteAccount(id, notifications, timelinesOnly) {
return (dispatch, getState) => {
dispatch(muteAccountRequest(id));
api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications }).then(response => {
api(getState).post(`/api/v1/accounts/${id}/mute`, { notifications, timelinesOnly }).then(response => {
// Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers
dispatch(muteAccountSuccess(response.data, getState().get('statuses')));
}).catch(error => {

View File

@ -13,6 +13,7 @@ export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL';
export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL';
export const MUTES_TOGGLE_HIDE_NOTIFICATIONS = 'MUTES_TOGGLE_HIDE_NOTIFICATIONS';
export const MUTES_TOGGLE_TIMELINES_ONLY = 'MUTES_TOGGLE_TIMELINES_ONLY';
export function fetchMutes() {
return (dispatch, getState) => {
@ -104,3 +105,9 @@ export function toggleHideNotifications() {
dispatch({ type: MUTES_TOGGLE_HIDE_NOTIFICATIONS });
};
}
export function toggleTimelinesOnly() {
return dispatch => {
dispatch({ type: MUTES_TOGGLE_TIMELINES_ONLY });
};
}

View File

@ -7,6 +7,7 @@ import Button from 'flavours/glitch/components/button';
import { closeModal } from 'flavours/glitch/actions/modal';
import { muteAccount } from 'flavours/glitch/actions/accounts';
import { toggleHideNotifications } from 'flavours/glitch/actions/mutes';
import { toggleTimelinesOnly } from 'flavours/glitch/actions/mutes';
const mapStateToProps = state => {
@ -14,13 +15,14 @@ const mapStateToProps = state => {
isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
account: state.getIn(['mutes', 'new', 'account']),
notifications: state.getIn(['mutes', 'new', 'notifications']),
timelinesOnly: state.getIn(['mutes', 'new', 'timelines_only']),
};
};
const mapDispatchToProps = dispatch => {
return {
onConfirm(account, notifications) {
dispatch(muteAccount(account.get('id'), notifications));
onConfirm(account, notifications, timelinesOnly) {
dispatch(muteAccount(account.get('id'), notifications, timelinesOnly));
},
onClose() {
@ -30,6 +32,10 @@ const mapDispatchToProps = dispatch => {
onToggleNotifications() {
dispatch(toggleHideNotifications());
},
onToggleTimelinesOnly() {
dispatch(toggleTimelinesOnly());
},
};
};
@ -41,9 +47,11 @@ export default class MuteModal extends React.PureComponent {
isSubmitting: PropTypes.bool.isRequired,
account: PropTypes.object.isRequired,
notifications: PropTypes.bool.isRequired,
timelinesOnly: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
onConfirm: PropTypes.func.isRequired,
onToggleNotifications: PropTypes.func.isRequired,
onTimelinesOnly: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
@ -53,7 +61,7 @@ export default class MuteModal extends React.PureComponent {
handleClick = () => {
this.props.onClose();
this.props.onConfirm(this.props.account, this.props.notifications);
this.props.onConfirm(this.props.account, this.props.notifications, this.props.timelinesOnly);
}
handleCancel = () => {
@ -68,8 +76,12 @@ export default class MuteModal extends React.PureComponent {
this.props.onToggleNotifications();
}
toggleTimelinesOnly = () => {
this.props.onToggleTimelinesOnly();
}
render () {
const { account, notifications } = this.props;
const { account, notifications, timelinesOnly } = this.props;
return (
<div className='modal-root__modal mute-modal'>
@ -88,6 +100,13 @@ export default class MuteModal extends React.PureComponent {
<Toggle id='mute-modal__hide-notifications-checkbox' checked={notifications} onChange={this.toggleNotifications} />
</label>
</div>
<div>
<label htmlFor='mute-modal__timelines-only-checkbox'>
<FormattedMessage id='mute_modal.timelines_only' defaultMessage='Hide from timelines only?' />
{' '}
<Toggle id='mute-modal__timelines-only-checkbox' checked={timelinesOnly} onChange={this.toggleTimelinesOnly} />
</label>
</div>
</div>
<div className='mute-modal__action-bar'>

View File

@ -3,6 +3,7 @@ import Immutable from 'immutable';
import {
MUTES_INIT_MODAL,
MUTES_TOGGLE_HIDE_NOTIFICATIONS,
MUTES_TOGGLE_TIMELINES_ONLY,
} from 'flavours/glitch/actions/mutes';
const initialState = Immutable.Map({
@ -10,6 +11,7 @@ const initialState = Immutable.Map({
isSubmitting: false,
account: null,
notifications: true,
timelinesOnly: false,
}),
});
@ -20,9 +22,12 @@ export default function mutes(state = initialState, action) {
state.setIn(['new', 'isSubmitting'], false);
state.setIn(['new', 'account'], action.account);
state.setIn(['new', 'notifications'], true);
state.setIn(['new', 'timelinesOnly'], false);
});
case MUTES_TOGGLE_HIDE_NOTIFICATIONS:
return state.updateIn(['new', 'notifications'], (old) => !old);
case MUTES_TOGGLE_TIMELINES_ONLY:
return state.updateIn(['new', 'timelines_only'], (old) => !old);
default:
return state;
}

View File

@ -25,7 +25,7 @@ module AccountInteractions
end
def muting_map(target_account_ids, account_id)
Mute.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |mute, mapping|
Mute.where(target_account_id: target_account_ids, account_id: account_id, timelines_only: false).each_with_object({}) do |mute, mapping|
mapping[mute.target_account_id] = {
notifications: mute.hide_notifications?,
}
@ -104,14 +104,15 @@ module AccountInteractions
.find_or_create_by!(target_account: other_account)
end
def mute!(other_account, notifications: nil)
def mute!(other_account, notifications: nil, timelines_only: nil)
notifications = true if notifications.nil?
mute = mute_relationships.create_with(hide_notifications: notifications).find_or_create_by!(target_account: other_account)
timelines_only = false if timelines_only.nil?
mute = mute_relationships.create_with(hide_notifications: notifications, timelines_only: timelines_only).find_or_create_by!(target_account: other_account)
remove_potential_friendship(other_account)
# When toggling a mute between hiding and allowing notifications, the mute will already exist, so the find_or_create_by! call will return the existing Mute without updating the hide_notifications attribute. Therefore, we check that hide_notifications? is what we want and set it if it isn't.
if mute.hide_notifications? != notifications
mute.update!(hide_notifications: notifications)
mute.update!(hide_notifications: notifications, timelines_only: timelines_only)
end
mute
@ -163,7 +164,7 @@ module AccountInteractions
end
def muting?(other_account)
mute_relationships.where(target_account: other_account).exists?
mute_relationships.where(target_account: other_account, timelines_only: false).exists?
end
def muting_conversation?(conversation)

View File

@ -9,6 +9,7 @@
# hide_notifications :boolean default(TRUE), not null
# account_id :bigint(8) not null
# target_account_id :bigint(8) not null
# timelines_only :boolean default(FALSE), not null
#
class Mute < ApplicationRecord

View File

@ -2,8 +2,8 @@
class REST::MuteSerializer < ActiveModel::Serializer
include RoutingHelper
attributes :id, :account, :target_account, :created_at, :hide_notifications
attributes :id, :account, :target_account, :created_at, :hide_notifications, :timelines_only
def account
REST::AccountSerializer.new(object.account)
@ -12,4 +12,4 @@ class REST::MuteSerializer < ActiveModel::Serializer
def target_account
REST::AccountSerializer.new(object.target_account)
end
end
end

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
class MuteService < BaseService
def call(account, target_account, notifications: nil)
def call(account, target_account, notifications: nil, timelines_only: nil)
return if account.id == target_account.id
mute = account.mute!(target_account, notifications: notifications)
mute = account.mute!(target_account, notifications: notifications, timelines_only: timelines_only)
if mute.hide_notifications?
BlockWorker.perform_async(account.id, target_account.id)

View File

@ -0,0 +1,5 @@
class AddTimelinesOnlyToMute < ActiveRecord::Migration[5.2]
def change
add_column :mutes, :timelines_only, :boolean, default: false, null: false
end
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_12_20_020441) do
ActiveRecord::Schema.define(version: 2019_12_21_164844) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@ -443,6 +443,7 @@ ActiveRecord::Schema.define(version: 2019_12_20_020441) do
t.boolean "hide_notifications", default: true, null: false
t.bigint "account_id", null: false
t.bigint "target_account_id", null: false
t.boolean "timelines_only", default: false, null: false
t.index ["account_id", "target_account_id"], name: "index_mutes_on_account_id_and_target_account_id", unique: true
t.index ["target_account_id"], name: "index_mutes_on_target_account_id"
end