Fix posts coming from public/hashtag streaming being marked as unquotable (#36860)
This commit is contained in:
@@ -46,11 +46,11 @@ export function importFetchedAccounts(accounts) {
|
||||
return importAccounts({ accounts: normalAccounts });
|
||||
}
|
||||
|
||||
export function importFetchedStatus(status) {
|
||||
return importFetchedStatuses([status]);
|
||||
export function importFetchedStatus(status, options = {}) {
|
||||
return importFetchedStatuses([status], options);
|
||||
}
|
||||
|
||||
export function importFetchedStatuses(statuses) {
|
||||
export function importFetchedStatuses(statuses, options = {}) {
|
||||
return (dispatch, getState) => {
|
||||
const accounts = [];
|
||||
const normalStatuses = [];
|
||||
@@ -58,7 +58,7 @@ export function importFetchedStatuses(statuses) {
|
||||
const filters = [];
|
||||
|
||||
function processStatus(status) {
|
||||
pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(['statuses', status.id])));
|
||||
pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(['statuses', status.id]), options));
|
||||
pushUnique(accounts, status.account);
|
||||
|
||||
if (status.filtered) {
|
||||
|
||||
@@ -27,9 +27,12 @@ function stripQuoteFallback(text) {
|
||||
return wrapper.innerHTML;
|
||||
}
|
||||
|
||||
export function normalizeStatus(status, normalOldStatus) {
|
||||
export function normalizeStatus(status, normalOldStatus, { bogusQuotePolicy = false }) {
|
||||
const normalStatus = { ...status };
|
||||
|
||||
if (bogusQuotePolicy)
|
||||
normalStatus.quote_approval = null;
|
||||
|
||||
normalStatus.account = status.account.id;
|
||||
|
||||
if (status.reblog && status.reblog.id) {
|
||||
@@ -109,6 +112,8 @@ export function normalizeStatus(status, normalOldStatus) {
|
||||
}
|
||||
|
||||
if (normalOldStatus) {
|
||||
normalStatus.quote_approval ||= normalOldStatus.quote_approval;
|
||||
|
||||
const list = normalOldStatus.get('media_attachments');
|
||||
if (normalStatus.media_attachments && list) {
|
||||
normalStatus.media_attachments.forEach(item => {
|
||||
|
||||
@@ -203,8 +203,8 @@ export function deleteStatusFail(id, error) {
|
||||
};
|
||||
}
|
||||
|
||||
export const updateStatus = status => dispatch =>
|
||||
dispatch(importFetchedStatus(status));
|
||||
export const updateStatus = (status, { bogusQuotePolicy }) => dispatch =>
|
||||
dispatch(importFetchedStatus(status, { bogusQuotePolicy }));
|
||||
|
||||
export function muteStatus(id) {
|
||||
return (dispatch) => {
|
||||
|
||||
@@ -52,6 +52,9 @@ const randomUpTo = max =>
|
||||
export const connectTimelineStream = (timelineId, channelName, params = {}, options = {}) => {
|
||||
const { messages } = getLocale();
|
||||
|
||||
// Public streams are currently not returning personalized quote policies
|
||||
const bogusQuotePolicy = channelName.startsWith('public') || channelName.startsWith('hashtag');
|
||||
|
||||
return connectStream(channelName, params, (dispatch, getState) => {
|
||||
// @ts-ignore
|
||||
const locale = getState().getIn(['meta', 'locale']);
|
||||
@@ -97,11 +100,11 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
|
||||
switch (data.event) {
|
||||
case 'update':
|
||||
// @ts-expect-error
|
||||
dispatch(updateTimeline(timelineId, JSON.parse(data.payload), options.accept));
|
||||
dispatch(updateTimeline(timelineId, JSON.parse(data.payload), { accept: options.accept, bogusQuotePolicy }));
|
||||
break;
|
||||
case 'status.update':
|
||||
// @ts-expect-error
|
||||
dispatch(updateStatus(JSON.parse(data.payload)));
|
||||
dispatch(updateStatus(JSON.parse(data.payload), { bogusQuotePolicy }));
|
||||
break;
|
||||
case 'delete':
|
||||
dispatch(deleteFromTimelines(data.payload));
|
||||
|
||||
@@ -32,7 +32,7 @@ export const loadPending = timeline => ({
|
||||
timeline,
|
||||
});
|
||||
|
||||
export function updateTimeline(timeline, status, accept) {
|
||||
export function updateTimeline(timeline, status, { accept = undefined, bogusQuotePolicy = false }) {
|
||||
return (dispatch, getState) => {
|
||||
if (typeof accept === 'function' && !accept(status)) {
|
||||
return;
|
||||
@@ -45,7 +45,7 @@ export function updateTimeline(timeline, status, accept) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(importFetchedStatus(status));
|
||||
dispatch(importFetchedStatus(status, { bogusQuotePolicy }));
|
||||
|
||||
dispatch({
|
||||
type: TIMELINE_UPDATE,
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
closeDropdownMenu,
|
||||
} from 'mastodon/actions/dropdown_menu';
|
||||
import { openModal, closeModal } from 'mastodon/actions/modal';
|
||||
import { fetchStatus } from 'mastodon/actions/statuses';
|
||||
import { CircularProgress } from 'mastodon/components/circular_progress';
|
||||
import { isUserTouching } from 'mastodon/is_mobile';
|
||||
import {
|
||||
@@ -302,6 +303,7 @@ interface DropdownProps<Item extends object | null = MenuItem> {
|
||||
*/
|
||||
scrollKey?: string;
|
||||
status?: ImmutableMap<string, unknown>;
|
||||
needsStatusRefresh?: boolean;
|
||||
forceDropdown?: boolean;
|
||||
renderItem?: RenderItemFn<Item>;
|
||||
renderHeader?: RenderHeaderFn<Item>;
|
||||
@@ -325,6 +327,7 @@ export const Dropdown = <Item extends object | null = MenuItem>({
|
||||
placement = 'bottom',
|
||||
offset = [5, 5],
|
||||
status,
|
||||
needsStatusRefresh,
|
||||
forceDropdown = false,
|
||||
renderItem,
|
||||
renderHeader,
|
||||
@@ -344,6 +347,7 @@ export const Dropdown = <Item extends object | null = MenuItem>({
|
||||
const prefetchAccountId = status
|
||||
? status.getIn(['account', 'id'])
|
||||
: undefined;
|
||||
const statusId = status?.get('id') as string | undefined;
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
if (buttonRef.current) {
|
||||
@@ -408,6 +412,15 @@ export const Dropdown = <Item extends object | null = MenuItem>({
|
||||
dispatch(fetchRelationships([prefetchAccountId]));
|
||||
}
|
||||
|
||||
if (needsStatusRefresh && statusId) {
|
||||
dispatch(
|
||||
fetchStatus(statusId, {
|
||||
forceFetch: true,
|
||||
alsoFetchContext: false,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (isUserTouching() && !forceDropdown) {
|
||||
dispatch(
|
||||
openModal({
|
||||
@@ -441,6 +454,8 @@ export const Dropdown = <Item extends object | null = MenuItem>({
|
||||
items,
|
||||
forceDropdown,
|
||||
handleClose,
|
||||
statusId,
|
||||
needsStatusRefresh,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import classNames from 'classnames';
|
||||
import { quoteComposeById } from '@/mastodon/actions/compose_typed';
|
||||
import { toggleReblog } from '@/mastodon/actions/interactions';
|
||||
import { openModal } from '@/mastodon/actions/modal';
|
||||
import { fetchStatus } from '@/mastodon/actions/statuses';
|
||||
import { quickBoosting } from '@/mastodon/initial_state';
|
||||
import type { ActionMenuItem } from '@/mastodon/models/dropdown_menu';
|
||||
import type { Status } from '@/mastodon/models/status';
|
||||
@@ -111,6 +112,7 @@ const BoostOrQuoteMenu: FC<ReblogButtonProps> = ({ status, counters }) => {
|
||||
|
||||
const statusId = status.get('id') as string;
|
||||
const wasBoosted = !!status.get('reblogged');
|
||||
const quoteApproval = status.get('quote_approval');
|
||||
|
||||
const showLoginPrompt = useCallback(() => {
|
||||
dispatch(
|
||||
@@ -167,9 +169,16 @@ const BoostOrQuoteMenu: FC<ReblogButtonProps> = ({ status, counters }) => {
|
||||
dispatch(toggleReblog(status.get('id'), true));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (quoteApproval === null) {
|
||||
dispatch(
|
||||
fetchStatus(statusId, { forceFetch: true, alsoFetchContext: false }),
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
[dispatch, isLoggedIn, showLoginPrompt, status],
|
||||
[dispatch, isLoggedIn, showLoginPrompt, status, quoteApproval, statusId],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -404,6 +404,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
<Dropdown
|
||||
scrollKey={scrollKey}
|
||||
status={status}
|
||||
needsStatusRefresh={quickBoosting && status.get('quote_approval') === null}
|
||||
items={menu}
|
||||
icon='ellipsis-h'
|
||||
iconComponent={MoreHorizIcon}
|
||||
|
||||
@@ -159,7 +159,7 @@ class Status extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
UNSAFE_componentWillMount () {
|
||||
this.props.dispatch(fetchStatus(this.props.params.statusId));
|
||||
this.props.dispatch(fetchStatus(this.props.params.statusId, { forceFetch: true }));
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
@@ -170,7 +170,7 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
UNSAFE_componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
|
||||
this.props.dispatch(fetchStatus(nextProps.params.statusId));
|
||||
this.props.dispatch(fetchStatus(nextProps.params.statusId, { forceFetch: true }));
|
||||
}
|
||||
|
||||
if (nextProps.status && nextProps.status.get('id') !== this.state.loadedStatusId) {
|
||||
|
||||
@@ -32,7 +32,7 @@ function getStatusResultFunction(
|
||||
};
|
||||
}
|
||||
|
||||
if (statusBase.get('isLoading')) {
|
||||
if (statusBase.get('isLoading') && !statusBase.get('content')) {
|
||||
return {
|
||||
status: null,
|
||||
loadingState: 'loading',
|
||||
@@ -74,7 +74,7 @@ function getStatusResultFunction(
|
||||
map.set('matched_filters', filtered);
|
||||
map.set('matched_media_filters', mediaFiltered);
|
||||
}),
|
||||
loadingState: 'complete'
|
||||
loadingState: statusBase.get('isLoading') ? 'loading' : 'complete'
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user