Browse Source

Split public timeline into "public timeline" which is local, and

"whole known network" which is what public timeline used to be

Only domain blocks with suspend severity will block PuSH subscriptions
Silenced accounts should not appear in conversations unless followed
closed-social-glitch-2
Eugen Rochko 7 years ago
parent
commit
4aa5ebe591
12 changed files with 143 additions and 51 deletions
  1. +1
    -0
      app/assets/javascripts/components/actions/compose.jsx
  2. +30
    -34
      app/assets/javascripts/components/actions/timelines.jsx
  3. +2
    -0
      app/assets/javascripts/components/containers/mastodon.jsx
  4. +73
    -0
      app/assets/javascripts/components/features/community_timeline/index.jsx
  5. +2
    -0
      app/assets/javascripts/components/features/compose/components/drawer.jsx
  6. +3
    -1
      app/assets/javascripts/components/features/getting_started/index.jsx
  7. +3
    -3
      app/assets/javascripts/components/features/public_timeline/index.jsx
  8. +4
    -0
      app/assets/javascripts/components/features/ui/containers/status_list_container.jsx
  9. +4
    -3
      app/assets/javascripts/components/locales/en.jsx
  10. +19
    -8
      app/assets/javascripts/components/reducers/timelines.jsx
  11. +1
    -1
      app/models/domain_block.rb
  12. +1
    -1
      app/models/status.rb

+ 1
- 0
app/assets/javascripts/components/actions/compose.jsx View File

@ -85,6 +85,7 @@ export function submitCompose() {
dispatch(updateTimeline('home', { ...response.data })); dispatch(updateTimeline('home', { ...response.data }));
if (response.data.in_reply_to_id === null && response.data.visibility === 'public') { if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
dispatch(updateTimeline('community', { ...response.data }));
dispatch(updateTimeline('public', { ...response.data })); dispatch(updateTimeline('public', { ...response.data }));
} }
}).catch(function (error) { }).catch(function (error) {

+ 30
- 34
app/assets/javascripts/components/actions/timelines.jsx View File

@ -1,4 +1,4 @@
import api from '../api'
import api, { getLinks } from '../api'
import Immutable from 'immutable'; import Immutable from 'immutable';
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE'; export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
@ -14,12 +14,13 @@ export const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL';
export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP'; export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';
export function refreshTimelineSuccess(timeline, statuses, skipLoading) {
export function refreshTimelineSuccess(timeline, statuses, skipLoading, next) {
return { return {
type: TIMELINE_REFRESH_SUCCESS, type: TIMELINE_REFRESH_SUCCESS,
timeline, timeline,
statuses, statuses,
skipLoading
skipLoading,
next
}; };
}; };
@ -69,25 +70,22 @@ export function refreshTimeline(timeline, id = null) {
const ids = getState().getIn(['timelines', timeline, 'items'], Immutable.List()); const ids = getState().getIn(['timelines', timeline, 'items'], Immutable.List());
const newestId = ids.size > 0 ? ids.first() : null; const newestId = ids.size > 0 ? ids.first() : null;
const params = getState().getIn(['timelines', timeline, 'params'], {});
const path = getState().getIn(['timelines', timeline, 'path'])(id);
let params = '';
let path = timeline;
let skipLoading = false; let skipLoading = false;
if (newestId !== null && getState().getIn(['timelines', timeline, 'loaded']) && (id === null || getState().getIn(['timelines', timeline, 'id']) === id)) { if (newestId !== null && getState().getIn(['timelines', timeline, 'loaded']) && (id === null || getState().getIn(['timelines', timeline, 'id']) === id)) {
params = `?since_id=${newestId}`;
skipLoading = true;
}
if (id) {
path = `${path}/${id}`
params.since_id = newestId;
skipLoading = true;
} }
dispatch(refreshTimelineRequest(timeline, id, skipLoading)); dispatch(refreshTimelineRequest(timeline, id, skipLoading));
api(getState).get(`/api/v1/timelines/${path}${params}`).then(function (response) {
dispatch(refreshTimelineSuccess(timeline, response.data, skipLoading));
}).catch(function (error) {
api(getState).get(path, { params }).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(refreshTimelineSuccess(timeline, response.data, skipLoading, next ? next.uri : null));
}).catch(error => {
dispatch(refreshTimelineFail(timeline, error, skipLoading)); dispatch(refreshTimelineFail(timeline, error, skipLoading));
}); });
}; };
@ -102,50 +100,48 @@ export function refreshTimelineFail(timeline, error, skipLoading) {
}; };
}; };
export function expandTimeline(timeline, id = null) {
export function expandTimeline(timeline) {
return (dispatch, getState) => { return (dispatch, getState) => {
const lastId = getState().getIn(['timelines', timeline, 'items'], Immutable.List()).last();
if (!lastId || getState().getIn(['timelines', timeline, 'isLoading'])) {
// If timeline is empty, don't try to load older posts since there are none
// Also if already loading
if (getState().getIn(['timelines', timeline, 'isLoading'])) {
return; return;
} }
dispatch(expandTimelineRequest(timeline, id));
const next = getState().getIn(['timelines', timeline, 'next']);
const params = getState().getIn(['timelines', timeline, 'params'], {});
let path = timeline;
if (id) {
path = `${path}/${id}`
if (next === null) {
return;
} }
api(getState).get(`/api/v1/timelines/${path}`, {
dispatch(expandTimelineRequest(timeline));
api(getState).get(next, {
params: { params: {
limit: 10,
max_id: lastId
...params,
limit: 10
} }
}).then(response => { }).then(response => {
dispatch(expandTimelineSuccess(timeline, response.data));
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(expandTimelineSuccess(timeline, response.data, next ? next.uri : null));
}).catch(error => { }).catch(error => {
dispatch(expandTimelineFail(timeline, error)); dispatch(expandTimelineFail(timeline, error));
}); });
}; };
}; };
export function expandTimelineRequest(timeline, id) {
export function expandTimelineRequest(timeline) {
return { return {
type: TIMELINE_EXPAND_REQUEST, type: TIMELINE_EXPAND_REQUEST,
timeline,
id
timeline
}; };
}; };
export function expandTimelineSuccess(timeline, statuses) {
export function expandTimelineSuccess(timeline, statuses, next) {
return { return {
type: TIMELINE_EXPAND_SUCCESS, type: TIMELINE_EXPAND_SUCCESS,
timeline, timeline,
statuses
statuses,
next
}; };
}; };

+ 2
- 0
app/assets/javascripts/components/containers/mastodon.jsx View File

@ -21,6 +21,7 @@ import UI from '../features/ui';
import Status from '../features/status'; import Status from '../features/status';
import GettingStarted from '../features/getting_started'; import GettingStarted from '../features/getting_started';
import PublicTimeline from '../features/public_timeline'; import PublicTimeline from '../features/public_timeline';
import CommunityTimeline from '../features/community_timeline';
import AccountTimeline from '../features/account_timeline'; import AccountTimeline from '../features/account_timeline';
import HomeTimeline from '../features/home_timeline'; import HomeTimeline from '../features/home_timeline';
import Compose from '../features/compose'; import Compose from '../features/compose';
@ -116,6 +117,7 @@ const Mastodon = React.createClass({
<Route path='getting-started' component={GettingStarted} /> <Route path='getting-started' component={GettingStarted} />
<Route path='timelines/home' component={HomeTimeline} /> <Route path='timelines/home' component={HomeTimeline} />
<Route path='timelines/public' component={PublicTimeline} /> <Route path='timelines/public' component={PublicTimeline} />
<Route path='timelines/community' component={CommunityTimeline} />
<Route path='timelines/tag/:id' component={HashtagTimeline} /> <Route path='timelines/tag/:id' component={HashtagTimeline} />
<Route path='notifications' component={Notifications} /> <Route path='notifications' component={Notifications} />

+ 73
- 0
app/assets/javascripts/components/features/community_timeline/index.jsx View File

@ -0,0 +1,73 @@
import { connect } from 'react-redux';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import StatusListContainer from '../ui/containers/status_list_container';
import Column from '../ui/components/column';
import {
refreshTimeline,
updateTimeline,
deleteFromTimelines
} from '../../actions/timelines';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import createStream from '../../stream';
const messages = defineMessages({
title: { id: 'column.community', defaultMessage: 'Public' }
});
const mapStateToProps = state => ({
accessToken: state.getIn(['meta', 'access_token'])
});
const CommunityTimeline = React.createClass({
propTypes: {
dispatch: React.PropTypes.func.isRequired,
intl: React.PropTypes.object.isRequired,
accessToken: React.PropTypes.string.isRequired
},
mixins: [PureRenderMixin],
componentDidMount () {
const { dispatch, accessToken } = this.props;
dispatch(refreshTimeline('community'));
this.subscription = createStream(accessToken, 'public:local', {
received (data) {
switch(data.event) {
case 'update':
dispatch(updateTimeline('community', JSON.parse(data.payload)));
break;
case 'delete':
dispatch(deleteFromTimelines(data.payload));
break;
}
}
});
},
componentWillUnmount () {
if (typeof this.subscription !== 'undefined') {
this.subscription.close();
this.subscription = null;
}
},
render () {
const { intl } = this.props;
return (
<Column icon='users' heading={intl.formatMessage(messages.title)}>
<ColumnBackButtonSlim />
<StatusListContainer type='community' emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The community timeline is empty. Write something publicly to get the ball rolling!' />} />
</Column>
);
},
});
export default connect(mapStateToProps)(injectIntl(CommunityTimeline));

+ 2
- 0
app/assets/javascripts/components/features/compose/components/drawer.jsx View File

@ -4,6 +4,7 @@ import { injectIntl, defineMessages } from 'react-intl';
const messages = defineMessages({ const messages = defineMessages({
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Public timeline' }, public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Public timeline' },
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Community timeline' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' } logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' }
}); });
@ -15,6 +16,7 @@ const Drawer = ({ children, withHeader, intl }) => {
header = ( header = (
<div className='drawer__header'> <div className='drawer__header'>
<Link title={intl.formatMessage(messages.start)} className='drawer__tab' to='/getting-started'><i className='fa fa-fw fa-asterisk' /></Link> <Link title={intl.formatMessage(messages.start)} className='drawer__tab' to='/getting-started'><i className='fa fa-fw fa-asterisk' /></Link>
<Link title={intl.formatMessage(messages.community)} className='drawer__tab' to='/timelines/community'><i className='fa fa-fw fa-users' /></Link>
<Link title={intl.formatMessage(messages.public)} className='drawer__tab' to='/timelines/public'><i className='fa fa-fw fa-globe' /></Link> <Link title={intl.formatMessage(messages.public)} className='drawer__tab' to='/timelines/public'><i className='fa fa-fw fa-globe' /></Link>
<a title={intl.formatMessage(messages.preferences)} className='drawer__tab' href='/settings/preferences'><i className='fa fa-fw fa-cog' /></a> <a title={intl.formatMessage(messages.preferences)} className='drawer__tab' href='/settings/preferences'><i className='fa fa-fw fa-cog' /></a>
<a title={intl.formatMessage(messages.logout)} className='drawer__tab' href='/auth/sign_out' data-method='delete'><i className='fa fa-fw fa-sign-out' /></a> <a title={intl.formatMessage(messages.logout)} className='drawer__tab' href='/auth/sign_out' data-method='delete'><i className='fa fa-fw fa-sign-out' /></a>

+ 3
- 1
app/assets/javascripts/components/features/getting_started/index.jsx View File

@ -7,7 +7,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
const messages = defineMessages({ const messages = defineMessages({
heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Public timeline' },
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Whole Known Network' },
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Public timeline' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Sign out' }, sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Sign out' },
@ -30,6 +31,7 @@ const GettingStarted = ({ intl, me }) => {
return ( return (
<Column icon='asterisk' heading={intl.formatMessage(messages.heading)}> <Column icon='asterisk' heading={intl.formatMessage(messages.heading)}>
<div style={{ position: 'relative' }}> <div style={{ position: 'relative' }}>
<ColumnLink icon='users' text={intl.formatMessage(messages.community_timeline)} to='/timelines/community' />
<ColumnLink icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' /> <ColumnLink icon='globe' text={intl.formatMessage(messages.public_timeline)} to='/timelines/public' />
<ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' /> <ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />
<ColumnLink icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' /> <ColumnLink icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />

+ 3
- 3
app/assets/javascripts/components/features/public_timeline/index.jsx View File

@ -7,12 +7,12 @@ import {
updateTimeline, updateTimeline,
deleteFromTimelines deleteFromTimelines
} from '../../actions/timelines'; } from '../../actions/timelines';
import { defineMessages, injectIntl } from 'react-intl';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ColumnBackButtonSlim from '../../components/column_back_button_slim'; import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import createStream from '../../stream'; import createStream from '../../stream';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'column.public', defaultMessage: 'Public' }
title: { id: 'column.public', defaultMessage: 'Whole Known Network' }
}); });
const mapStateToProps = state => ({ const mapStateToProps = state => ({
@ -63,7 +63,7 @@ const PublicTimeline = React.createClass({
return ( return (
<Column icon='globe' heading={intl.formatMessage(messages.title)}> <Column icon='globe' heading={intl.formatMessage(messages.title)}>
<ColumnBackButtonSlim /> <ColumnBackButtonSlim />
<StatusListContainer type='public' />
<StatusListContainer type='public' emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other instances to fill it up' />} />
</Column> </Column>
); );
}, },

+ 4
- 0
app/assets/javascripts/components/features/ui/containers/status_list_container.jsx View File

@ -3,6 +3,7 @@ import StatusList from '../../../components/status_list';
import { expandTimeline, scrollTopTimeline } from '../../../actions/timelines'; import { expandTimeline, scrollTopTimeline } from '../../../actions/timelines';
import Immutable from 'immutable'; import Immutable from 'immutable';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { debounce } from 'react-decoration';
const getStatusIds = createSelector([ const getStatusIds = createSelector([
(state, { type }) => state.getIn(['settings', type], Immutable.Map()), (state, { type }) => state.getIn(['settings', type], Immutable.Map()),
@ -40,15 +41,18 @@ const mapStateToProps = (state, props) => ({
const mapDispatchToProps = (dispatch, { type, id }) => ({ const mapDispatchToProps = (dispatch, { type, id }) => ({
@debounce(300, true)
onScrollToBottom () { onScrollToBottom () {
dispatch(scrollTopTimeline(type, false)); dispatch(scrollTopTimeline(type, false));
dispatch(expandTimeline(type, id)); dispatch(expandTimeline(type, id));
}, },
@debounce(300, true)
onScrollToTop () { onScrollToTop () {
dispatch(scrollTopTimeline(type, true)); dispatch(scrollTopTimeline(type, true));
}, },
@debounce(500)
onScroll () { onScroll () {
dispatch(scrollTopTimeline(type, false)); dispatch(scrollTopTimeline(type, false));
} }

+ 4
- 3
app/assets/javascripts/components/locales/en.jsx View File

@ -28,8 +28,8 @@ const en = {
"getting_started.about_developer": "The developer of this project can be followed as Gargron@mastodon.social", "getting_started.about_developer": "The developer of this project can be followed as Gargron@mastodon.social",
"getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on github at {github}.", "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on github at {github}.",
"column.home": "Home", "column.home": "Home",
"column.mentions": "Mentions",
"column.public": "Public",
"column.community": "Public",
"column.public": "Whole Known Network",
"column.notifications": "Notifications", "column.notifications": "Notifications",
"tabs_bar.compose": "Compose", "tabs_bar.compose": "Compose",
"tabs_bar.home": "Home", "tabs_bar.home": "Home",
@ -45,7 +45,8 @@ const en = {
"compose_form.unlisted": "Do not display in public timeline", "compose_form.unlisted": "Do not display in public timeline",
"navigation_bar.edit_profile": "Edit profile", "navigation_bar.edit_profile": "Edit profile",
"navigation_bar.preferences": "Preferences", "navigation_bar.preferences": "Preferences",
"navigation_bar.public_timeline": "Public timeline",
"navigation_bar.community_timeline": "Public timeline",
"navigation_bar.public_timeline": "Whole Known Network",
"navigation_bar.logout": "Logout", "navigation_bar.logout": "Logout",
"reply_indicator.cancel": "Cancel", "reply_indicator.cancel": "Cancel",
"search.placeholder": "Search", "search.placeholder": "Search",

+ 19
- 8
app/assets/javascripts/components/reducers/timelines.jsx View File

@ -31,20 +31,27 @@ import Immutable from 'immutable';
const initialState = Immutable.Map({ const initialState = Immutable.Map({
home: Immutable.Map({ home: Immutable.Map({
path: () => '/api/v1/timelines/home',
next: null,
isLoading: false, isLoading: false,
loaded: false, loaded: false,
top: true, top: true,
items: Immutable.List() items: Immutable.List()
}), }),
mentions: Immutable.Map({
public: Immutable.Map({
path: () => '/api/v1/timelines/public',
next: null,
isLoading: false, isLoading: false,
loaded: false, loaded: false,
top: true, top: true,
items: Immutable.List() items: Immutable.List()
}), }),
public: Immutable.Map({
community: Immutable.Map({
path: () => '/api/v1/timelines/public',
next: null,
params: { local: true },
isLoading: false, isLoading: false,
loaded: false, loaded: false,
top: true, top: true,
@ -52,6 +59,8 @@ const initialState = Immutable.Map({
}), }),
tag: Immutable.Map({ tag: Immutable.Map({
path: (id) => `/api/v1/timelines/tag/${id}`,
next: null,
isLoading: false, isLoading: false,
id: null, id: null,
loaded: false, loaded: false,
@ -81,7 +90,7 @@ const normalizeStatus = (state, status) => {
return state; return state;
}; };
const normalizeTimeline = (state, timeline, statuses, replacen> = false) => {
const normalizeTimeline = (state, timeline, statuses, next) => {
let ids = Immutable.List(); let ids = Immutable.List();
const loaded = state.getIn([timeline, 'loaded']); const loaded = state.getIn([timeline, 'loaded']);
@ -92,11 +101,12 @@ const normalizeTimeline = (state, timeline, statuses, replace = false) => {
state = state.setIn([timeline, 'loaded'], true); state = state.setIn([timeline, 'loaded'], true);
state = state.setIn([timeline, 'isLoading'], false); state = state.setIn([timeline, 'isLoading'], false);
state = state.setIn([timeline, 'next'], next);
return state.updateIn([timeline, 'items'], Immutable.List(), list => (loaded ? list.unshift(...ids) : ids)); return state.updateIn([timeline, 'items'], Immutable.List(), list => (loaded ? list.unshift(...ids) : ids));
}; };
const appendNormalizedTimeline = (state, timeline, statuses) => {
const appendNormalizedTimeline = (state, timeline, statuses, next) => {
let moreIds = Immutable.List(); let moreIds = Immutable.List();
statuses.forEach((status, i) => { statuses.forEach((status, i) => {
@ -105,6 +115,7 @@ const appendNormalizedTimeline = (state, timeline, statuses) => {
}); });
state = state.setIn([timeline, 'isLoading'], false); state = state.setIn([timeline, 'isLoading'], false);
state = state.setIn([timeline, 'next'], next);
return state.updateIn([timeline, 'items'], Immutable.List(), list => list.push(...moreIds)); return state.updateIn([timeline, 'items'], Immutable.List(), list => list.push(...moreIds));
}; };
@ -169,7 +180,7 @@ const deleteStatus = (state, id, accountId, references, reblogOf) => {
} }
// Remove references from timelines // Remove references from timelines
['home', 'mentions', 'public', 'tag'].forEach(function (timeline) {
['home', 'public', 'community', 'tag'].forEach(function (timeline) {
state = state.updateIn([timeline, 'items'], list => list.filterNot(item => item === id)); state = state.updateIn([timeline, 'items'], list => list.filterNot(item => item === id));
}); });
@ -221,7 +232,7 @@ const normalizeContext = (state, id, ancestors, descendants) => {
}; };
const resetTimeline = (state, timeline, id) => { const resetTimeline = (state, timeline, id) => {
if (timeline === 'tag' && state.getIn([timeline, 'id']) !== id) {
if (timeline === 'tag' && typeof id !== 'undefined' && state.getIn([timeline, 'id']) !== id) {
state = state.update(timeline, map => map state = state.update(timeline, map => map
.set('id', id) .set('id', id)
.set('isLoading', true) .set('isLoading', true)
@ -243,9 +254,9 @@ export default function timelines(state = initialState, action) {
case TIMELINE_EXPAND_FAIL: case TIMELINE_EXPAND_FAIL:
return state.setIn([action.timeline, 'isLoading'], false); return state.setIn([action.timeline, 'isLoading'], false);
case TIMELINE_REFRESH_SUCCESS: case TIMELINE_REFRESH_SUCCESS:
return normalizeTimeline(state, action.timeline, Immutable.fromJS(action.statuses));
return normalizeTimeline(state, action.timeline, Immutable.fromJS(action.statuses), action.next);
case TIMELINE_EXPAND_SUCCESS: case TIMELINE_EXPAND_SUCCESS:
return appendNormalizedTimeline(state, action.timeline, Immutable.fromJS(action.statuses));
return appendNormalizedTimeline(state, action.timeline, Immutable.fromJS(action.statuses), action.next);
case TIMELINE_UPDATE: case TIMELINE_UPDATE:
return updateTimeline(state, action.timeline, Immutable.fromJS(action.status), action.references); return updateTimeline(state, action.timeline, Immutable.fromJS(action.status), action.references);
case TIMELINE_DELETE: case TIMELINE_DELETE:

+ 1
- 1
app/models/domain_block.rb View File

@ -6,6 +6,6 @@ class DomainBlock < ApplicationRecord
validates :domain, presence: true, uniqueness: true validates :domain, presence: true, uniqueness: true
def self.blocked?(domain) def self.blocked?(domain)
where(domain: domain).exists?
where(domain: domain, severity: :suspend).exists?
end end
end end

+ 1
- 1
app/models/status.rb View File

@ -192,6 +192,6 @@ class Status < ApplicationRecord
private private
def filter_from_context?(status, account) def filter_from_context?(status, account)
account&.blocking?(status.account_id) || !status.permitted?(account)
account&.blocking?(status.account_id) || (status.account.silenced? && !account&.following?(status.account_id)) || !status.permitted?(account)
end end
end end

Loading…
Cancel
Save