Unverified Commit f029b8f0 authored by Martin Kraft's avatar Martin Kraft Committed by GitHub
Browse files

Merge branch 'master' into advanced-permissions-phase-2

parents 0b4cb401 947d5808
......@@ -55,13 +55,13 @@ export default class DeletePostModal extends React.PureComponent {
teamName,
} = this.props;
const {data} = await actions.deleteAndRemovePost(post);
const result = await actions.deleteAndRemovePost(post);
if (post.id === focusedPostId && channelName) {
browserHistory.push('/' + teamName + '/channels/' + channelName);
}
if (data) {
if (result.data) {
this.onHide();
}
}
......
......@@ -4,12 +4,15 @@
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {General, Posts} from 'mattermost-redux/constants';
import ChannelStore from 'stores/channel_store.jsx';
import {canManageMembers} from 'utils/channel_utils.jsx';
import {Constants, PostTypes} from 'utils/constants.jsx';
import {formatText} from 'utils/text_formatting.jsx';
import * as Utils from 'utils/utils.jsx';
import CombinedSystemMessage from 'components/post_view/combined_system_message';
import PostAddChannelMember from 'components/post_view/post_add_channel_member';
function renderUsername(value, options) {
......@@ -298,19 +301,19 @@ function renderChannelDeletedMessage(post, options) {
}
const systemMessageRenderers = {
[PostTypes.JOIN_CHANNEL]: renderJoinChannelMessage,
[PostTypes.LEAVE_CHANNEL]: renderLeaveChannelMessage,
[PostTypes.ADD_TO_CHANNEL]: renderAddToChannelMessage,
[PostTypes.REMOVE_FROM_CHANNEL]: renderRemoveFromChannelMessage,
[PostTypes.JOIN_TEAM]: renderJoinTeamMessage,
[PostTypes.LEAVE_TEAM]: renderLeaveTeamMessage,
[PostTypes.ADD_TO_TEAM]: renderAddToTeamMessage,
[PostTypes.REMOVE_FROM_TEAM]: renderRemoveFromTeamMessage,
[PostTypes.HEADER_CHANGE]: renderHeaderChangeMessage,
[PostTypes.DISPLAYNAME_CHANGE]: renderDisplayNameChangeMessage,
[PostTypes.CONVERT_CHANNEL]: renderConvertChannelToPrivateMessage,
[PostTypes.PURPOSE_CHANGE]: renderPurposeChangeMessage,
[PostTypes.CHANNEL_DELETED]: renderChannelDeletedMessage,
[Posts.POST_TYPES.JOIN_CHANNEL]: renderJoinChannelMessage,
[Posts.POST_TYPES.LEAVE_CHANNEL]: renderLeaveChannelMessage,
[Posts.POST_TYPES.ADD_TO_CHANNEL]: renderAddToChannelMessage,
[Posts.POST_TYPES.REMOVE_FROM_CHANNEL]: renderRemoveFromChannelMessage,
[Posts.POST_TYPES.JOIN_TEAM]: renderJoinTeamMessage,
[Posts.POST_TYPES.LEAVE_TEAM]: renderLeaveTeamMessage,
[Posts.POST_TYPES.ADD_TO_TEAM]: renderAddToTeamMessage,
[Posts.POST_TYPES.REMOVE_FROM_TEAM]: renderRemoveFromTeamMessage,
[Posts.POST_TYPES.HEADER_CHANGE]: renderHeaderChangeMessage,
[Posts.POST_TYPES.DISPLAYNAME_CHANGE]: renderDisplayNameChangeMessage,
[Posts.POST_TYPES.CONVERT_CHANNEL]: renderConvertChannelToPrivateMessage,
[Posts.POST_TYPES.PURPOSE_CHANGE]: renderPurposeChangeMessage,
[Posts.POST_TYPES.CHANNEL_DELETED]: renderChannelDeletedMessage,
};
export function renderSystemMessage(post, options) {
......@@ -319,7 +322,7 @@ export function renderSystemMessage(post, options) {
const isUserCanManageMembers = canManageMembers(channel);
const isEphemeral = Utils.isPostEphemeral(post);
if ((channel.type === Constants.PRIVATE_CHANNEL || channel.type === Constants.OPEN_CHANNEL) &&
if ((channel.type === General.PRIVATE_CHANNEL || channel.type === General.OPEN_CHANNEL) &&
isUserCanManageMembers &&
isEphemeral
) {
......@@ -336,8 +339,17 @@ export function renderSystemMessage(post, options) {
return null;
} else if (systemMessageRenderers[post.type]) {
return systemMessageRenderers[post.type](post, options);
} else if (post.type === PostTypes.EPHEMERAL_ADD_TO_CHANNEL) {
} else if (post.type === Posts.POST_TYPES.EPHEMERAL_ADD_TO_CHANNEL) {
return renderAddToChannelMessage(post, options);
} else if (post.type === Posts.POST_TYPES.COMBINED_USER_ACTIVITY) {
const {allUserIds, messageData} = post.props.user_activity;
return (
<CombinedSystemMessage
allUserIds={allUserIds}
messageData={messageData}
/>
);
}
return null;
......
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import PropTypes from 'prop-types';
import React from 'react';
import {FormattedHTMLMessage} from 'react-intl';
import {Posts} from 'mattermost-redux/constants';
import {
getDisplayNameByUserId,
localizeMessage,
} from 'utils/utils.jsx';
import LastUsers from './last_users';
const {
JOIN_CHANNEL, ADD_TO_CHANNEL, REMOVE_FROM_CHANNEL, LEAVE_CHANNEL,
JOIN_TEAM, ADD_TO_TEAM, REMOVE_FROM_TEAM, LEAVE_TEAM,
} = Posts.POST_TYPES;
const postTypeMessage = {
[JOIN_CHANNEL]: {
one: {
id: 'combined_system_message.joined_channel.one',
defaultMessage: '{firstUser} <b>joined the channel</b>.',
},
two: {
id: 'combined_system_message.joined_channel.two',
defaultMessage: '{firstUser} and {secondUser} <b>joined the channel</b>.',
},
many_expanded: {
id: 'combined_system_message.joined_channel.many_expanded',
defaultMessage: '{users} and {lastUser} <b>joined the channel</b>.',
},
},
[ADD_TO_CHANNEL]: {
one: {
id: 'combined_system_message.added_to_channel.one',
defaultMessage: '{firstUser} <b>added to the channel</b> by {actor}.',
},
one_you: {
id: 'combined_system_message.added_to_channel.one_you',
defaultMessage: 'You were <b>added to the channel</b> by {actor}.',
},
two: {
id: 'combined_system_message.added_to_channel.two',
defaultMessage: '{firstUser} and {secondUser} <b>added to the channel</b> by {actor}.',
},
many_expanded: {
id: 'combined_system_message.added_to_channel.many_expanded',
defaultMessage: '{users} and {lastUser} were <b>added to the channel</b> by {actor}.',
},
},
[REMOVE_FROM_CHANNEL]: {
one: {
id: 'combined_system_message.removed_from_channel.one',
defaultMessage: '{firstUser} was <b>removed from the channel</b>.',
},
one_you: {
id: 'combined_system_message.removed_from_channel.one_you',
defaultMessage: 'You were <b>removed from the channel</b>.',
},
two: {
id: 'combined_system_message.removed_from_channel.two',
defaultMessage: '{firstUser} and {secondUser} were <b>removed from the channel</b>.',
},
many_expanded: {
id: 'combined_system_message.removed_from_channel.many_expanded',
defaultMessage: '{users} and {lastUser} were <b>removed from the channel</b>.',
},
},
[LEAVE_CHANNEL]: {
one: {
id: 'combined_system_message.left_channel.one',
defaultMessage: '{firstUser} <b>left the channel</b>.',
},
two: {
id: 'combined_system_message.left_channel.two',
defaultMessage: '{firstUser} and {secondUser} <b>left the channel</b>.',
},
many_expanded: {
id: 'combined_system_message.left_channel.many_expanded',
defaultMessage: '{users} and {lastUser} <b>left the channel</b>.',
},
},
[JOIN_TEAM]: {
one: {
id: 'combined_system_message.joined_team.one',
defaultMessage: '{firstUser} <b>joined the team</b>.',
},
two: {
id: 'combined_system_message.joined_team.two',
defaultMessage: '{firstUser} and {secondUser} <b>joined the team</b>.',
},
many_expanded: {
id: 'combined_system_message.joined_team.many_expanded',
defaultMessage: '{users} and {lastUser} <b>joined the team</b>.',
},
},
[ADD_TO_TEAM]: {
one: {
id: 'combined_system_message.added_to_team.one',
defaultMessage: '{firstUser} <b>added to the team</b> by {actor}.',
},
one_you: {
id: 'combined_system_message.added_to_team.one_you',
defaultMessage: 'You were <b>added to the team</b> by {actor}.',
},
two: {
id: 'combined_system_message.added_to_team.two',
defaultMessage: '{firstUser} and {secondUser} <b>added to the team</b> by {actor}.',
},
many_expanded: {
id: 'combined_system_message.added_to_team.many_expanded',
defaultMessage: '{users} and {lastUser} were <b>added to the team</b> by {actor}.',
},
},
[REMOVE_FROM_TEAM]: {
one: {
id: 'combined_system_message.removed_from_team.one',
defaultMessage: '{firstUser} was <b>removed from the team</b>.',
},
one_you: {
id: 'combined_system_message.removed_from_team.one_you',
defaultMessage: 'You were <b>removed from the team</b>.',
},
two: {
id: 'combined_system_message.removed_from_team.two',
defaultMessage: '{firstUser} and {secondUser} were <b>removed from the team</b>.',
},
many_expanded: {
id: 'combined_system_message.removed_from_team.many_expanded',
defaultMessage: '{users} and {lastUser} were <b>removed from the team</b>.',
},
},
[LEAVE_TEAM]: {
one: {
id: 'combined_system_message.left_team.one',
defaultMessage: '{firstUser} <b>left the team</b>.',
},
two: {
id: 'combined_system_message.left_team.two',
defaultMessage: '{firstUser} and {secondUser} <b>left the team</b>.',
},
many_expanded: {
id: 'combined_system_message.left_team.many_expanded',
defaultMessage: '{users} and {lastUser} <b>left the team</b>.',
},
},
};
export default class CombinedSystemMessage extends React.PureComponent {
static propTypes = {
currentUserId: PropTypes.string.isRequired,
messageData: PropTypes.array.isRequired,
allUserIds: PropTypes.array.isRequired,
actions: PropTypes.shape({
getMissingProfilesByIds: PropTypes.func.isRequired,
}).isRequired,
};
constructor(props) {
super(props);
this.state = {
missingProfiles: [],
};
}
componentDidMount() {
this.loadMissingProfiles();
}
loadMissingProfiles = async () => {
const {
actions,
allUserIds,
} = this.props;
const missingProfiles = await actions.getMissingProfilesByIds(allUserIds);
this.setState({missingProfiles});
}
getDisplayNameByIds = (userIds = []) => {
const {currentUserId} = this.props;
const displayNames = userIds.
filter((userId) => {
return userId !== currentUserId;
}).
map((userId) => {
return getDisplayNameByUserId(userId, true);
});
const userInProp = userIds.includes(currentUserId);
if (userInProp) {
displayNames.unshift(localizeMessage('combined_system_message.you', 'You'));
}
return displayNames;
}
renderFormattedMessage(postType, userIds, actorId) {
const userDisplayNames = this.getDisplayNameByIds(userIds);
let actor = actorId ? this.getDisplayNameByIds([actorId])[0] : '';
if (actorId === this.props.currentUserId) {
actor = actor.toLowerCase();
}
const firstUser = userDisplayNames[0];
const numOthers = userDisplayNames.length - 1;
let formattedMessage;
if (numOthers === 0) {
formattedMessage = (
<FormattedHTMLMessage
id={postTypeMessage[postType].one.id}
defaultMessage={postTypeMessage[postType].one.defaultMessage}
values={{
firstUser,
actor,
}}
/>
);
if (
userIds[0] === this.props.currentUserId &&
postTypeMessage[postType].one_you
) {
formattedMessage = (
<FormattedHTMLMessage
id={postTypeMessage[postType].one_you.id}
defaultMessage={postTypeMessage[postType].one_you.defaultMessage}
values={{
actor,
}}
/>
);
}
} else if (numOthers === 1) {
formattedMessage = (
<FormattedHTMLMessage
id={postTypeMessage[postType].two.id}
defaultMessage={postTypeMessage[postType].two.defaultMessage}
values={{
firstUser,
secondUser: userDisplayNames[1],
actor,
}}
/>
);
} else {
formattedMessage = (
<LastUsers
actor={actor}
expandedLocale={postTypeMessage[postType].many_expanded}
postType={postType}
userDisplayNames={userDisplayNames}
/>
);
}
return formattedMessage;
}
render() {
const {messageData} = this.props;
return (
<React.Fragment>
{messageData.map(({postType, userIds, actorId}) => {
return (
<React.Fragment key={postType + actorId}>
<span>
{this.renderFormattedMessage(postType, userIds, actorId)}
</span>
<br/>
</React.Fragment>
);
})}
</React.Fragment>
);
}
}
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {getMissingProfilesByIds} from 'mattermost-redux/actions/users';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import CombinedSystemMessage from './combined_system_message.jsx';
function mapStateToProps(state) {
return {
currentUserId: getCurrentUserId(state),
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
getMissingProfilesByIds,
}, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(CombinedSystemMessage);
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import PropTypes from 'prop-types';
import React from 'react';
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
import {Posts} from 'mattermost-redux/constants';
const typeMessage = {
[Posts.POST_TYPES.ADD_TO_CHANNEL]: {
id: 'last_users_message.added_to_channel.type',
defaultMessage: 'were <b>added to the channel</b> by {actor}.',
},
[Posts.POST_TYPES.JOIN_CHANNEL]: {
id: 'last_users_message.joined_channel.type',
defaultMessage: '<b>joined the channel</b>.',
},
[Posts.POST_TYPES.LEAVE_CHANNEL]: {
id: 'last_users_message.left_channel.type',
defaultMessage: '<b>left the channel</b>.',
},
[Posts.POST_TYPES.REMOVE_FROM_CHANNEL]: {
id: 'last_users_message.removed_from_channel.type',
defaultMessage: 'were <b>removed from the channel</b>.',
},
[Posts.POST_TYPES.ADD_TO_TEAM]: {
id: 'last_users_message.added_to_team.type',
defaultMessage: 'were <b>added to the team</b> by {actor}.',
},
[Posts.POST_TYPES.JOIN_TEAM]: {
id: 'last_users_message.joined_team.type',
defaultMessage: '<b>joined the team</b>.',
},
[Posts.POST_TYPES.LEAVE_TEAM]: {
id: 'last_users_message.left_team.type',
defaultMessage: '<b>left the team</b>.',
},
[Posts.POST_TYPES.REMOVE_FROM_TEAM]: {
id: 'last_users_message.removed_from_team.type',
defaultMessage: 'were <b>removed from the team</b>.',
},
};
export default class LastUsers extends React.PureComponent {
static propTypes = {
actor: PropTypes.string,
expandedLocale: PropTypes.object.isRequired,
postType: PropTypes.string.isRequired,
userDisplayNames: PropTypes.array.isRequired,
};
constructor(props) {
super(props);
this.state = {
expand: false,
};
}
handleOnClick = (e) => {
e.preventDefault();
this.setState({expand: true});
}
render() {
const {expand} = this.state;
const {
actor,
expandedLocale,
postType,
userDisplayNames,
} = this.props;
const lastIndex = userDisplayNames.length - 1;
if (expand) {
return (
<FormattedHTMLMessage
id={expandedLocale.id}
defaultMessage={expandedLocale.defaultMessage}
values={{
users: userDisplayNames.slice(0, lastIndex).join(', '),
lastUser: userDisplayNames[lastIndex],
actor,
}}
/>
);
}
return (
<React.Fragment>
<FormattedMessage
id={'last_users_message.first'}
defaultMessage={'{firstUser} and '}
values={{
firstUser: userDisplayNames[0],
}}
/>
<a onClick={this.handleOnClick}>
<FormattedMessage
id={'last_users_message.others'}
defaultMessage={'{numOthers} others '}
values={{
numOthers: lastIndex,
}}
/>
</a>
<FormattedHTMLMessage
id={typeMessage[postType].id}
defaultMessage={typeMessage[postType].defaultMessage}
values={{
actor,
}}
/>
</React.Fragment>
);
}
}
......@@ -6,12 +6,15 @@ import React from 'react';
import ReactDOM from 'react-dom';
import {FormattedMessage} from 'react-intl';
import {isUserActivityPost} from 'mattermost-redux/utils/post_utils';
import Constants, {PostTypes} from 'utils/constants.jsx';
import DelayedAction from 'utils/delayed_action.jsx';
import EventTypes from 'utils/event_types.jsx';
import GlobalEventEmitter from 'utils/global_event_emitter.jsx';
import * as UserAgent from 'utils/user_agent.jsx';
import * as Utils from 'utils/utils.jsx';
import LoadingScreen from 'components/loading_screen.jsx';
import DateSeparator from 'components/post_view/date_separator.jsx';
......@@ -466,7 +469,8 @@ export default class PostList extends React.PureComponent {
if (
post == null ||
post.type === PostTypes.EPHEMERAL_ADD_TO_CHANNEL
post.type === PostTypes.EPHEMERAL_ADD_TO_CHANNEL ||
isUserActivityPost(post.type)
) {
continue;
}
......
......@@ -6,6 +6,8 @@ import {connect} from 'react-redux';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {updateTeam, removeTeamIcon, setTeamIcon} from 'mattermost-redux/actions/teams';
import {Permissions} from 'mattermost-redux/constants';
import {haveITeamPermission} from 'mattermost-redux/selectors/entities/roles';
import TeamGeneralTab from './team_general_tab.jsx';
......@@ -13,9 +15,12 @@ function mapStateToProps(state, ownProps) {
const config = getConfig(state);
const maxFileSize = parseInt(config.MaxFileSize, 10);
const canInviteTeamMembers = haveITeamPermission(state, {team: ownProps.team.id, permission: Permissions.INVITE_USER});
return {
...ownProps,
maxFileSize,
canInviteTeamMembers,
};
}
......
......@@ -27,6 +27,7 @@ export default class GeneralTab extends React.Component {
removeTeamIcon: PropTypes.func.isRequired,
setTeamIcon: PropTypes.func.isRequired,
}).isRequired,
canInviteTeamMembers: PropTypes.bool.isRequired,
}