Fix MM-61710 (#29248)
* Fix MM-61710 * Fix test * Make more secure the secureGetFromRecord * Revert changes related to redux posts * Move segureGetFromRecord * Fix test * Use hasOwn * Address feedback --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
99f242527e
Коммит
25ff7a3779
@@ -9,6 +9,7 @@ import type {UserProfile} from '@mattermost/types/users';
|
||||
|
||||
import {Posts} from 'mattermost-redux/constants';
|
||||
import type {MessageData} from 'mattermost-redux/utils/post_list';
|
||||
import {secureGetFromRecord} from 'mattermost-redux/utils/post_utils';
|
||||
|
||||
import Markdown from 'components/markdown';
|
||||
|
||||
@@ -264,7 +265,8 @@ export class CombinedSystemMessage extends React.PureComponent<Props> {
|
||||
return userId !== currentUserId && userId !== currentUsername;
|
||||
}).
|
||||
map((userId) => {
|
||||
return allUsernames[userId] ? `@${allUsernames[userId]}` : someone;
|
||||
const username = secureGetFromRecord(allUsernames, userId);
|
||||
return username ? `@${username}` : someone;
|
||||
}).
|
||||
filter((username) => {
|
||||
return username && username !== '';
|
||||
@@ -299,11 +301,16 @@ export class CombinedSystemMessage extends React.PureComponent<Props> {
|
||||
singleline: true,
|
||||
};
|
||||
|
||||
const selectedPostTypeMessage = secureGetFromRecord(postTypeMessage, postType);
|
||||
if (!selectedPostTypeMessage) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
if (numOthers > 1) {
|
||||
return (
|
||||
<LastUsers
|
||||
actor={actor}
|
||||
expandedLocale={postTypeMessage[postType].many_expanded}
|
||||
expandedLocale={selectedPostTypeMessage.many_expanded}
|
||||
formatOptions={options}
|
||||
postType={postType}
|
||||
usernames={usernames}
|
||||
@@ -313,16 +320,16 @@ export class CombinedSystemMessage extends React.PureComponent<Props> {
|
||||
|
||||
let localeHolder: MessageDescriptor = {};
|
||||
if (numOthers === 0) {
|
||||
localeHolder = postTypeMessage[postType].one;
|
||||
localeHolder = selectedPostTypeMessage.one;
|
||||
|
||||
if (
|
||||
(userIds[0] === this.props.currentUserId || userIds[0] === this.props.currentUsername) &&
|
||||
postTypeMessage[postType].one_you
|
||||
selectedPostTypeMessage.one_you
|
||||
) {
|
||||
localeHolder = postTypeMessage[postType].one_you;
|
||||
localeHolder = selectedPostTypeMessage.one_you;
|
||||
}
|
||||
} else if (numOthers === 1) {
|
||||
localeHolder = postTypeMessage[postType].two;
|
||||
localeHolder = selectedPostTypeMessage.two;
|
||||
}
|
||||
|
||||
const formattedMessage = formatMessage(localeHolder, {firstUser, secondUser, actor});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {defineMessages, injectIntl} from 'react-intl';
|
||||
import type {IntlShape, MessageDescriptor} from 'react-intl';
|
||||
|
||||
import {Posts} from 'mattermost-redux/constants';
|
||||
import {secureGetFromRecord} from 'mattermost-redux/utils/post_utils';
|
||||
|
||||
import Markdown from 'components/markdown';
|
||||
|
||||
@@ -121,10 +122,12 @@ export class LastUsers extends React.PureComponent<Props, State> {
|
||||
{numOthers: lastIndex},
|
||||
);
|
||||
|
||||
const actorMessage = formatMessage(
|
||||
{id: typeMessage[postType].id, defaultMessage: typeMessage[postType].defaultMessage},
|
||||
const selectedTypeMessage = secureGetFromRecord(typeMessage, postType);
|
||||
|
||||
const actorMessage = selectedTypeMessage ? formatMessage(
|
||||
{id: selectedTypeMessage.id, defaultMessage: selectedTypeMessage.defaultMessage},
|
||||
{actor},
|
||||
);
|
||||
) : '';
|
||||
|
||||
return (
|
||||
<span>
|
||||
|
||||
@@ -7,6 +7,7 @@ import styled, {css} from 'styled-components';
|
||||
import type {PostAction, PostActionOption} from '@mattermost/types/integration_actions';
|
||||
|
||||
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {secureGetFromRecord} from 'mattermost-redux/utils/post_utils';
|
||||
import {changeOpacity} from 'mattermost-redux/utils/theme_utils';
|
||||
|
||||
import Markdown from 'components/markdown';
|
||||
@@ -51,8 +52,8 @@ const ActionButton = ({
|
||||
if (action.style) {
|
||||
const STATUS_COLORS = getStatusColors(theme);
|
||||
hexColor =
|
||||
STATUS_COLORS[action.style] ||
|
||||
theme[action.style] ||
|
||||
secureGetFromRecord(STATUS_COLORS, action.style) ||
|
||||
secureGetFromRecord(theme, action.style) ||
|
||||
(action.style.match('^#(?:[0-9a-fA-F]{3}){1,2}$') && action.style);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import type {ConnectedProps} from 'react-redux';
|
||||
|
||||
import type {PostAction} from '@mattermost/types/integration_actions';
|
||||
|
||||
import {secureGetFromRecord} from 'mattermost-redux/utils/post_utils';
|
||||
|
||||
import {autocompleteChannels} from 'actions/channel_actions';
|
||||
import {autocompleteUsers} from 'actions/user_actions';
|
||||
import {selectAttachmentMenuAction} from 'actions/views/posts';
|
||||
@@ -22,7 +24,7 @@ export type OwnProps = {
|
||||
|
||||
function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
|
||||
const actions = state.views.posts.menuActions[ownProps.postId];
|
||||
const selected = (ownProps.action && ownProps.action.id) ? actions && actions[ownProps.action && ownProps.action.id] : undefined;
|
||||
const selected = (ownProps.action?.id) ? secureGetFromRecord(actions, ownProps.action.id) : undefined;
|
||||
|
||||
return {
|
||||
selected,
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {
|
||||
import type {PostImage} from '@mattermost/types/posts';
|
||||
|
||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||
import {secureGetFromRecord} from 'mattermost-redux/utils/post_utils';
|
||||
|
||||
import {trackEvent} from 'actions/telemetry_actions';
|
||||
|
||||
@@ -101,7 +102,7 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
|
||||
if (!attachment.thumb_url) {
|
||||
return;
|
||||
}
|
||||
if (!this.props.imagesMetadata || (this.props.imagesMetadata && !this.props.imagesMetadata[attachment.thumb_url])) {
|
||||
if (!secureGetFromRecord(this.props.imagesMetadata, attachment.thumb_url)) {
|
||||
this.handleHeightReceived(height);
|
||||
}
|
||||
};
|
||||
@@ -111,7 +112,7 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
|
||||
if (!attachment.image_url) {
|
||||
return;
|
||||
}
|
||||
if (!this.props.imagesMetadata || (this.props.imagesMetadata && !this.props.imagesMetadata[attachment.image_url])) {
|
||||
if (!secureGetFromRecord(this.props.imagesMetadata, attachment.image_url)) {
|
||||
this.handleHeightReceived(height);
|
||||
}
|
||||
};
|
||||
@@ -369,7 +370,7 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
|
||||
<ExternalImage
|
||||
key={'attachment__author-icon'}
|
||||
src={attachment.author_icon}
|
||||
imageMetadata={this.props.imagesMetadata && this.props.imagesMetadata[attachment.author_icon]}
|
||||
imageMetadata={secureGetFromRecord(this.props.imagesMetadata, attachment.author_icon)}
|
||||
>
|
||||
{(iconUrl) => (
|
||||
<img
|
||||
@@ -459,7 +460,7 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
|
||||
|
||||
let image;
|
||||
if (attachment.image_url) {
|
||||
const imageMetadata = this.props.imagesMetadata && this.props.imagesMetadata[attachment.image_url];
|
||||
const imageMetadata = secureGetFromRecord(this.props.imagesMetadata, attachment.image_url);
|
||||
|
||||
image = (
|
||||
<div className='attachment__image-container'>
|
||||
@@ -485,7 +486,7 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
|
||||
if (attachment.footer) {
|
||||
let footerIcon;
|
||||
if (attachment.footer_icon) {
|
||||
const footerIconMetadata = this.props.imagesMetadata && this.props.imagesMetadata[attachment.footer_icon];
|
||||
const footerIconMetadata = secureGetFromRecord(this.props.imagesMetadata, attachment.footer_icon);
|
||||
|
||||
footerIcon = (
|
||||
<ExternalImage
|
||||
@@ -515,7 +516,7 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
|
||||
|
||||
let thumb;
|
||||
if (attachment.thumb_url) {
|
||||
const thumbMetadata = this.props.imagesMetadata && this.props.imagesMetadata[attachment.thumb_url];
|
||||
const thumbMetadata = secureGetFromRecord(this.props.imagesMetadata, attachment.thumb_url);
|
||||
|
||||
thumb = (
|
||||
<div className='attachment__thumb-container'>
|
||||
|
||||
@@ -1099,7 +1099,9 @@ export function getNeededAtMentionedUsernamesAndGroups(state: GlobalState, posts
|
||||
|
||||
if (attachment.fields) {
|
||||
for (const field of attachment.fields) {
|
||||
findNeededUsernamesAndGroups(field.value);
|
||||
if (typeof field.value === 'string') {
|
||||
findNeededUsernamesAndGroups(field.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
} from 'mattermost-redux/selectors/entities/common';
|
||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getDirectShowPreferences, getTeammateNameDisplaySetting} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {secureGetFromRecord} from 'mattermost-redux/utils/post_utils';
|
||||
import {
|
||||
displayUsername,
|
||||
filterProfilesStartingWithTerm,
|
||||
@@ -687,7 +688,7 @@ export function makeGetProfilesByIdsAndUsernames(): (
|
||||
|
||||
if (allUserIds && allUserIds.length > 0) {
|
||||
const profilesById = allUserIds.
|
||||
filter((userId) => allProfilesById[userId]).
|
||||
filter((userId) => secureGetFromRecord(allProfilesById, userId)).
|
||||
map((userId) => allProfilesById[userId]);
|
||||
|
||||
if (profilesById && profilesById.length > 0) {
|
||||
@@ -697,7 +698,7 @@ export function makeGetProfilesByIdsAndUsernames(): (
|
||||
|
||||
if (allUsernames && allUsernames.length > 0) {
|
||||
const profilesByUsername = allUsernames.
|
||||
filter((username) => allProfilesByUsername[username]).
|
||||
filter((username) => secureGetFromRecord(allProfilesByUsername, username)).
|
||||
map((username) => allProfilesByUsername[username]);
|
||||
|
||||
if (profilesByUsername && profilesByUsername.length > 0) {
|
||||
|
||||
@@ -249,3 +249,7 @@ export function ensureString(v: unknown) {
|
||||
export function ensureNumber(v: unknown) {
|
||||
return typeof v === 'number' ? v : 0;
|
||||
}
|
||||
|
||||
export function secureGetFromRecord<T>(v: Record<string, T> | undefined, key: string) {
|
||||
return typeof v === 'object' && v && Object.hasOwn(v, key) ? v[key] : undefined;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,14 @@ import configureStore from 'store';
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
import {addTimeToTimestamp, TimeInformation} from 'utils/utils';
|
||||
|
||||
jest.mock('mattermost-redux/selectors/entities/users');
|
||||
jest.mock('mattermost-redux/selectors/entities/users', () => {
|
||||
const originalModule = jest.requireActual('mattermost-redux/selectors/entities/users');
|
||||
return {
|
||||
...originalModule,
|
||||
getCurrentUser: jest.fn(),
|
||||
getUser: jest.fn(),
|
||||
};
|
||||
});
|
||||
jest.mock('mattermost-redux/selectors/entities/general');
|
||||
jest.mock('mattermost-redux/selectors/entities/preferences');
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {MarketplaceApp, MarketplacePlugin} from '@mattermost/types/marketpl
|
||||
|
||||
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
||||
import {isPlugin} from 'mattermost-redux/utils/marketplace';
|
||||
import {secureGetFromRecord} from 'mattermost-redux/utils/post_utils';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
@@ -45,6 +46,6 @@ export const getApp = (state: GlobalState, id: string): MarketplaceApp | undefin
|
||||
|
||||
export const getFilter = (state: GlobalState): string => state.views.marketplace.filter;
|
||||
|
||||
export const getInstalling = (state: GlobalState, id: string): boolean => Boolean(state.views.marketplace.installing[id]);
|
||||
export const getInstalling = (state: GlobalState, id: string): boolean => Boolean(secureGetFromRecord(state.views.marketplace.installing, id));
|
||||
|
||||
export const getError = (state: GlobalState, id: string): string => state.views.marketplace.errors[id];
|
||||
export const getError = (state: GlobalState, id: string): string | undefined => secureGetFromRecord(state.views.marketplace.errors, id);
|
||||
|
||||
Ссылка в новой задаче
Block a user