Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions app/controllers/api/v1/domain_mutes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# frozen_string_literal: true

class Api::V1::DomainMutesController < Api::BaseController
MUTE_LIMIT = 100

before_action -> { doorkeeper_authorize! :follow, :read, :'read:mutes' }, only: :show
before_action -> { doorkeeper_authorize! :follow, :write, :'write:mutes' }, except: :show
before_action :require_user!
after_action :insert_pagination_headers, only: :show

def show
@mutes = load_domain_mutes
render json: @mutes.map { |domain_mute| domain_mute.as_json(only: %i(domain hide_from_home)) }
end

def create
current_account.mute_domain!(
domain_mute_params[:domain],
hide_from_home: domain_mute_params[:hide_from_home]
)

# TODO
# AfterAccountDomainMuteWorker.perform_async(current_account.id, domain_mute_params[:domain])
render_empty
end

def destroy
current_account.unmute_domain!(domain_mute_params[:domain])
render_empty
end

private

def load_domain_mutes
account_domain_mutes.paginate_by_max_id(
limit_param(MUTE_LIMIT),
params[:max_id],
params[:since_id]
)
end

def account_domain_mutes
current_account.domain_mutes
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

def next_path
api_v1_domain_mutes_url pagination_params(max_id: pagination_max_id) if records_continue?
end

def prev_path
api_v1_domain_mutes_url pagination_params(since_id: pagination_since_id) unless @mutes.empty?
end

def pagination_max_id
@mutes.last.id
end

def pagination_since_id
@mutes.first.id
end

def records_continue?
@mutes.size == limit_param(MUTE_LIMIT)
end

def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params)
end

def domain_mute_params
params.permit(:domain, :hide_from_home)
end
end
232 changes: 232 additions & 0 deletions app/javascript/flavours/glitch/actions/domain_mutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import api, { getLinks } from '../api';
import { openModal } from './modal';

export const DOMAIN_MUTE_REQUEST = 'DOMAIN_MUTE_REQUEST';
export const DOMAIN_MUTE_SUCCESS = 'DOMAIN_MUTE_SUCCESS';
export const DOMAIN_MUTE_FAIL = 'DOMAIN_MUTE_FAIL';

export const DOMAIN_MUTE_HOME_TIMELINE_REQUEST = 'DOMAIN_MUTE_HOME_TIMELINE_REQUEST';
export const DOMAIN_MUTE_HOME_TIMELINE_SUCCESS = 'DOMAIN_MUTE_HOME_TIMELINE_SUCCESS';
export const DOMAIN_MUTE_HOME_TIMELINE_FAIL = 'DOMAIN_MUTE_HOME_TIMELINE_FAIL';

export const DOMAIN_UNMUTE_REQUEST = 'DOMAIN_UNMUTE_REQUEST';
export const DOMAIN_UNMUTE_SUCCESS = 'DOMAIN_UNMUTE_SUCCESS';
export const DOMAIN_UNMUTE_FAIL = 'DOMAIN_UNMUTE_FAIL';

export const DOMAIN_MUTES_FETCH_REQUEST = 'DOMAIN_MUTES_FETCH_REQUEST';
export const DOMAIN_MUTES_FETCH_SUCCESS = 'DOMAIN_MUTES_FETCH_SUCCESS';
export const DOMAIN_MUTES_FETCH_FAIL = 'DOMAIN_MUTES_FETCH_FAIL';

export const DOMAIN_MUTES_EXPAND_REQUEST = 'DOMAIN_MUTES_EXPAND_REQUEST';
export const DOMAIN_MUTES_EXPAND_SUCCESS = 'DOMAIN_MUTES_EXPAND_SUCCESS';
export const DOMAIN_MUTES_EXPAND_FAIL = 'DOMAIN_MUTES_EXPAND_FAIL';

export const DOMAIN_MUTES_INIT_MODAL = 'DOMAIN_MUTES_INIT_MODAL';
export const DOMAIN_MUTES_TOGGLE_HIDE_FROM_HOME = 'DOMAIN_MUTES_TOGGLE_HIDE_FROM_HOME';

export function muteDomain(domain, hideFromHome) {
return (dispatch, getState) => {
dispatch(muteDomainRequest(domain));

api(getState).post('/api/v1/domain_mutes', { domain, hide_from_home: hideFromHome }).then(() => {
const at_domain = '@' + domain;
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));

dispatch(muteDomainSuccess(domain, accounts));
}).catch(err => {
dispatch(muteDomainFail(domain, err));
});
};
}

export function excludeDomainHomeTimeline(domain, excludeHomeTimeline) {
return (dispatch, getState) => {
dispatch(excludeDomainHomeTimelineRequest(domain, excludeHomeTimeline));

api(getState).post('/api/v1/domain_mutes', { domain, hide_from_home: excludeHomeTimeline }).then(() => {
const at_domain = '@' + domain;
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));

dispatch(excludeDomainHomeTimelineSuccess(domain, excludeHomeTimeline, accounts));
}).catch(err => {
dispatch(excludeDomainHomeTimelineFail(domain, excludeHomeTimeline, err));
});
};
}

export function muteDomainRequest(domain) {
return {
type: DOMAIN_MUTE_REQUEST,
domain,
};
}

export function excludeDomainHomeTimelineRequest(domain, excludeHomeTimeline) {
return {
type: DOMAIN_MUTE_HOME_TIMELINE_REQUEST,
domain,
home_timeline: excludeHomeTimeline,
};
}

export function muteDomainSuccess(domain, accounts) {
return {
type: DOMAIN_MUTE_SUCCESS,
domain,
accounts,
};
}

export function muteDomainFail(domain, error) {
return {
type: DOMAIN_MUTE_FAIL,
domain,
error,
};
}

export function excludeDomainHomeTimelineSuccess(domain, excludeHomeTimeline, accounts) {
return {
type: DOMAIN_MUTE_HOME_TIMELINE_SUCCESS,
domain,
homeTimeline: excludeHomeTimeline,
accounts,
};
}

export function excludeDomainHomeTimelineFail(domain, excludeHomeTimeline, error) {
return {
type: DOMAIN_MUTE_HOME_TIMELINE_FAIL,
domain,
homeTimeline: excludeHomeTimeline,
error,
};
}

export function unmuteDomain(domain) {
return (dispatch, getState) => {
dispatch(unmuteDomainRequest(domain));

api(getState).delete('/api/v1/domain_mutes', { params: { domain } }).then(() => {
const at_domain = '@' + domain;
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
dispatch(unmuteDomainSuccess(domain, accounts));
}).catch(err => {
dispatch(unmuteDomainFail(domain, err));
});
};
}

export function unmuteDomainRequest(domain) {
return {
type: DOMAIN_UNMUTE_REQUEST,
domain,
};
}

export function unmuteDomainSuccess(domain, accounts) {
return {
type: DOMAIN_UNMUTE_SUCCESS,
domain,
accounts,
};
}

export function unmuteDomainFail(domain, error) {
return {
type: DOMAIN_UNMUTE_FAIL,
domain,
error,
};
}

export function fetchDomainMutes() {
return (dispatch, getState) => {
dispatch(fetchDomainMutesRequest());

api(getState).get('/api/v1/domain_mutes').then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(fetchDomainMutesSuccess(response.data, next ? next.uri : null));
}).catch(err => {
dispatch(fetchDomainMutesFail(err));
});
};
}

export function fetchDomainMutesRequest() {
return {
type: DOMAIN_MUTES_FETCH_REQUEST,
};
}

export function fetchDomainMutesSuccess(domains, next) {
return {
type: DOMAIN_MUTES_FETCH_SUCCESS,
domains,
next,
};
}

export function fetchDomainMutesFail(error) {
return {
type: DOMAIN_MUTES_FETCH_FAIL,
error,
};
}

export function expandDomainMutes() {
return (dispatch, getState) => {
const url = getState().getIn(['domain_lists', 'mutes', 'next']);

if (!url) {
return;
}

dispatch(expandDomainMutesRequest());

api(getState).get(url).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(expandDomainMutesSuccess(response.data, next ? next.uri : null));
}).catch(err => {
dispatch(expandDomainMutesFail(err));
});
};
}

export function expandDomainMutesRequest() {
return {
type: DOMAIN_MUTES_EXPAND_REQUEST,
};
}

export function expandDomainMutesSuccess(domains, next) {
return {
type: DOMAIN_MUTES_EXPAND_SUCCESS,
domains,
next,
};
}

export function expandDomainMutesFail(error) {
return {
type: DOMAIN_MUTES_EXPAND_FAIL,
error,
};
}

export function initDomainMuteModal(domain) {
return dispatch => {
dispatch({
type: DOMAIN_MUTES_INIT_MODAL,
domain,
});

dispatch(openModal('DOMAIN_MUTE'));
};
}

export function toggleHideFromHome() {
return dispatch => {
dispatch({ type: DOMAIN_MUTES_TOGGLE_HIDE_FROM_HOME });
};
}
69 changes: 69 additions & 0 deletions app/javascript/flavours/glitch/components/muted_domain.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';
import PropTypes from 'prop-types';
import IconButton from './icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';

const messages = defineMessages({
unmute_domain: { id: 'account.unmute_domain', defaultMessage: 'Unmute domain {domain}' },
exclude_domain_from_home_timeline: { id: 'account.exclude_domain_from_home_timeline', defaultMessage: 'Exclude domain {domain} from home timeline' },
include_domain_from_home_timeline: { id: 'account.include_domain_from_home_timeline', defaultMessage: 'Include domain {domain} from home timeline' },
});

class MutedDomain extends ImmutablePureComponent {

static propTypes = {
domain: PropTypes.object.isRequired,
onUnmuteDomain: PropTypes.func.isRequired,
onExcludeDomainHomeTimeline: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};

handleDomainUnmute = () => {
this.props.onUnmuteDomain(this.props.domain.domain);
};

handleDomainExcludeHomeTimeline = () => {
this.props.onExcludeDomainHomeTimeline(this.props.domain.domain, true);
};

handleDomainIncludeHomeTimeline = () => {
this.props.onExcludeDomainHomeTimeline(this.props.domain.domain, false);
};

render () {
const { domain: { domain, hide_from_home }, intl } = this.props;

const buttons = [];
if (hide_from_home) {
buttons.push(
<IconButton active icon='eye' title={intl.formatMessage(messages.include_domain_from_home_timeline, { domain })} onClick={this.handleDomainIncludeHomeTimeline} />,
);
} else {
buttons.push(
<IconButton active icon='eye-slash' title={intl.formatMessage(messages.exclude_domain_from_home_timeline, { domain })} onClick={this.handleDomainExcludeHomeTimeline} />,
);
}

buttons.push(
<IconButton active icon='volume-up' title={intl.formatMessage(messages.unmute_domain, { domain })} onClick={this.handleDomainUnmute} />,
);

return (
<div className='domain'>
<div className='domain__wrapper'>
<span className='domain__domain-name'>
<strong>{domain}</strong>
</span>

<div className='domain__buttons'>
{buttons}
</div>
</div>
</div>
);
}

}

export default injectIntl(MutedDomain);
Loading