mirror of
https://github.com/mattermost/mattermost.git
synced 2026-05-28 04:35:04 -04:00
MM-64428 - user tag invite filtering (#31226)
* MM-64428 - user tag invite filtering * fix lint issues * remove unnecesary line * update translations and skip mysql tests * simplify the solution so in abac channels the invitation link is never shown * finish clean up of unnecessary code * clean up and remove no longer necessary translations * remove leftover props and remove no longer needed tests after simplification --------- Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
parent
f1893e4837
commit
e99aa4e430
5 changed files with 151 additions and 43 deletions
|
|
@ -1260,6 +1260,7 @@ func (a *App) filterOutOfChannelMentions(c request.CTX, sender *model.User, post
|
|||
// Differentiate between mentionedUsersInTheTeam who can and can't be added to the channel
|
||||
var outOfChannelUsers model.UserSlice
|
||||
var outOfGroupsUsers model.UserSlice
|
||||
|
||||
if channel.IsGroupConstrained() {
|
||||
nonMemberIDs, err := a.FilterNonGroupChannelMembers(teamUsers.IDs(), channel)
|
||||
if err != nil {
|
||||
|
|
@ -1289,6 +1290,8 @@ func makeOutOfChannelMentionPost(sender *model.User, post *model.Post, outOfChan
|
|||
|
||||
ephemeralPostId := model.NewId()
|
||||
var message string
|
||||
|
||||
// Generate message for users who can be invited
|
||||
if len(outOfChannelUsers) == 1 {
|
||||
message = T("api.post.check_for_out_of_channel_mentions.message.one", map[string]any{
|
||||
"Username": ocUsernames[0],
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ exports[`components/post_view/PostAddChannelMember should match snapshot, empty
|
|||
|
||||
exports[`components/post_view/PostAddChannelMember should match snapshot, more than 3 users 1`] = `
|
||||
<Fragment>
|
||||
<p>
|
||||
<p
|
||||
key="invitable"
|
||||
>
|
||||
<span>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
|
|
@ -67,7 +69,9 @@ exports[`components/post_view/PostAddChannelMember should match snapshot, more t
|
|||
|
||||
exports[`components/post_view/PostAddChannelMember should match snapshot, more than 3 users 2`] = `
|
||||
<Fragment>
|
||||
<p>
|
||||
<p
|
||||
key="invitable"
|
||||
>
|
||||
<span>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
|
|
@ -129,7 +133,9 @@ exports[`components/post_view/PostAddChannelMember should match snapshot, more t
|
|||
|
||||
exports[`components/post_view/PostAddChannelMember should match snapshot, private channel 1`] = `
|
||||
<Fragment>
|
||||
<p>
|
||||
<p
|
||||
key="invitable"
|
||||
>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
mentionName="username_1"
|
||||
|
|
@ -158,7 +164,9 @@ exports[`components/post_view/PostAddChannelMember should match snapshot, privat
|
|||
|
||||
exports[`components/post_view/PostAddChannelMember should match snapshot, public channel 1`] = `
|
||||
<Fragment>
|
||||
<p>
|
||||
<p
|
||||
key="invitable"
|
||||
>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
mentionName="username_1"
|
||||
|
|
@ -185,9 +193,45 @@ exports[`components/post_view/PostAddChannelMember should match snapshot, public
|
|||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`components/post_view/PostAddChannelMember should match snapshot, with ABAC policy enforced 1`] = `
|
||||
<p>
|
||||
<span>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
key="username_1"
|
||||
mentionName="username_1"
|
||||
/>
|
||||
<span
|
||||
key="1"
|
||||
>
|
||||
,
|
||||
</span>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
key="username_2"
|
||||
mentionName="username_2"
|
||||
/>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage=" and "
|
||||
id="post_body.check_for_out_of_channel_mentions.link.and"
|
||||
key="2"
|
||||
/>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
key="username_3"
|
||||
mentionName="username_3"
|
||||
/>
|
||||
</span>
|
||||
|
||||
did not get notified by this mention because they are not in the channel.
|
||||
</p>
|
||||
`;
|
||||
|
||||
exports[`components/post_view/PostAddChannelMember should match snapshot, with no-groups usernames 1`] = `
|
||||
<Fragment>
|
||||
<p>
|
||||
<p
|
||||
key="invitable"
|
||||
>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
mentionName="username_1"
|
||||
|
|
@ -211,7 +255,9 @@ exports[`components/post_view/PostAddChannelMember should match snapshot, with n
|
|||
id="post_body.check_for_out_of_channel_mentions.message_last"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<p
|
||||
key="out-of-groups"
|
||||
>
|
||||
<Connect(Component)
|
||||
channelId="channel_id"
|
||||
mentionName="user_id_2"
|
||||
|
|
|
|||
|
|
@ -17,15 +17,18 @@ import PostAddChannelMember from './post_add_channel_member';
|
|||
|
||||
type OwnProps = {
|
||||
postId: string;
|
||||
userIds: string[];
|
||||
}
|
||||
|
||||
function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
|
||||
const post = getPost(state, ownProps.postId) || {};
|
||||
let channelType = '';
|
||||
let isPolicyEnforced = false;
|
||||
if (post && post.channel_id) {
|
||||
const channel = getChannel(state, post.channel_id);
|
||||
if (channel && channel.type) {
|
||||
channelType = channel.type;
|
||||
isPolicyEnforced = Boolean(channel.policy_enforced);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -33,6 +36,7 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
|
|||
channelType,
|
||||
currentUser: getCurrentUser(state),
|
||||
post,
|
||||
isPolicyEnforced,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ describe('components/post_view/PostAddChannelMember', () => {
|
|||
addChannelMember: jest.fn(),
|
||||
},
|
||||
noGroupsUsernames: [],
|
||||
isPolicyEnforced: false,
|
||||
};
|
||||
|
||||
test('should match snapshot, empty postId', () => {
|
||||
|
|
@ -140,4 +141,39 @@ describe('components/post_view/PostAddChannelMember', () => {
|
|||
const wrapper = shallow(<PostAddChannelMember {...props}/>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot, with ABAC policy enforced', () => {
|
||||
const props: Props = {
|
||||
...requiredProps,
|
||||
usernames: ['username_1', 'username_2', 'username_3'],
|
||||
isPolicyEnforced: true,
|
||||
};
|
||||
const wrapper = shallow(<PostAddChannelMember {...props}/>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should never show invite links when policy is enforced (ABAC channels)', () => {
|
||||
const props: Props = {
|
||||
...requiredProps,
|
||||
usernames: ['username_1', 'username_2'],
|
||||
noGroupsUsernames: [],
|
||||
isPolicyEnforced: true,
|
||||
};
|
||||
const wrapper = shallow(<PostAddChannelMember {...props}/>);
|
||||
expect(wrapper.find('.PostBody_addChannelMemberLink')).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('should show single consolidated message for ABAC channels regardless of user types', () => {
|
||||
const props: Props = {
|
||||
...requiredProps,
|
||||
usernames: ['user1', 'user2'],
|
||||
noGroupsUsernames: ['user3'],
|
||||
isPolicyEnforced: true,
|
||||
};
|
||||
const wrapper = shallow(<PostAddChannelMember {...props}/>);
|
||||
|
||||
// Should render only one consolidated message with no invite links
|
||||
expect(wrapper.find('p')).toHaveLength(1);
|
||||
expect(wrapper.find('.PostBody_addChannelMemberLink')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export interface Props {
|
|||
userIds: string[];
|
||||
usernames: string[];
|
||||
noGroupsUsernames: string[];
|
||||
isPolicyEnforced: boolean;
|
||||
actions: Actions;
|
||||
}
|
||||
|
||||
|
|
@ -146,11 +147,33 @@ export default class PostAddChannelMember extends React.PureComponent<Props, Sta
|
|||
}
|
||||
|
||||
render() {
|
||||
const {channelType, postId, usernames, noGroupsUsernames} = this.props;
|
||||
const {channelType, postId, usernames, noGroupsUsernames, isPolicyEnforced} = this.props;
|
||||
if (!postId || !channelType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// For ABAC channels (policy enforced), NEVER show invite links - only show notification message
|
||||
if (isPolicyEnforced) {
|
||||
// Combine all users into a single message without any invite functionality
|
||||
const allUsers = [...usernames, ...noGroupsUsernames];
|
||||
const allUsersAtMentions = this.generateAtMentions(allUsers);
|
||||
|
||||
if (allUsers.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const messageText = 'did not get notified by this mention because they are not in the channel.';
|
||||
|
||||
return (
|
||||
<p>
|
||||
{allUsersAtMentions}
|
||||
{' '}
|
||||
{messageText}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
// Regular flow for non-ABAC channels
|
||||
let link;
|
||||
if (channelType === Constants.PRIVATE_CHANNEL) {
|
||||
link = (
|
||||
|
|
@ -168,44 +191,32 @@ export default class PostAddChannelMember extends React.PureComponent<Props, Sta
|
|||
);
|
||||
}
|
||||
|
||||
let outOfChannelMessagePart;
|
||||
const outOfChannelAtMentions = this.generateAtMentions(usernames);
|
||||
if (usernames.length === 1) {
|
||||
outOfChannelMessagePart = (
|
||||
// Separate invitable users from group-constrained users
|
||||
const invitableUsers = usernames.filter((username) => !noGroupsUsernames.includes(username));
|
||||
const outOfGroupsUsers = noGroupsUsernames;
|
||||
|
||||
const messages = [];
|
||||
|
||||
// Handle invitable users with invite functionality
|
||||
if (invitableUsers.length > 0) {
|
||||
const invitableAtMentions = this.generateAtMentions(invitableUsers);
|
||||
const invitableMessagePart = invitableUsers.length === 1 ? (
|
||||
<FormattedMessage
|
||||
id='post_body.check_for_out_of_channel_mentions.message.one'
|
||||
defaultMessage='did not get notified by this mention because they are not in the channel. Would you like to '
|
||||
/>
|
||||
);
|
||||
} else if (usernames.length > 1) {
|
||||
outOfChannelMessagePart = (
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='post_body.check_for_out_of_channel_mentions.message.multiple'
|
||||
defaultMessage='did not get notified by this mention because they are not in the channel. Would you like to '
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let outOfGroupsMessagePart;
|
||||
const outOfGroupsAtMentions = this.generateAtMentions(noGroupsUsernames);
|
||||
if (noGroupsUsernames.length) {
|
||||
outOfGroupsMessagePart = (
|
||||
<FormattedMessage
|
||||
id='post_body.check_for_out_of_channel_groups_mentions.message'
|
||||
defaultMessage='did not get notified by this mention because they are not in the channel. They cannot be added to the channel because they are not a member of the linked groups. To add them to this channel, they must be added to the linked groups.'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let outOfChannelMessage = null;
|
||||
let outOfGroupsMessage = null;
|
||||
|
||||
if (usernames.length) {
|
||||
outOfChannelMessage = (
|
||||
<p>
|
||||
{outOfChannelAtMentions}
|
||||
messages.push(
|
||||
<p key='invitable'>
|
||||
{invitableAtMentions}
|
||||
{' '}
|
||||
{outOfChannelMessagePart}
|
||||
{invitableMessagePart}
|
||||
<a
|
||||
className='PostBody_addChannelMemberLink'
|
||||
onClick={this.handleAddChannelMember}
|
||||
|
|
@ -213,27 +224,35 @@ export default class PostAddChannelMember extends React.PureComponent<Props, Sta
|
|||
{link}
|
||||
</a>
|
||||
<FormattedMessage
|
||||
id={'post_body.check_for_out_of_channel_mentions.message_last'}
|
||||
defaultMessage={'? They will have access to all message history.'}
|
||||
id='post_body.check_for_out_of_channel_mentions.message_last'
|
||||
defaultMessage='? They will have access to all message history.'
|
||||
/>
|
||||
</p>
|
||||
</p>,
|
||||
);
|
||||
}
|
||||
|
||||
if (noGroupsUsernames.length) {
|
||||
outOfGroupsMessage = (
|
||||
<p>
|
||||
// Handle users not in required groups with specific messaging
|
||||
if (outOfGroupsUsers.length > 0) {
|
||||
const outOfGroupsAtMentions = this.generateAtMentions(outOfGroupsUsers);
|
||||
const outOfGroupsMessagePart = (
|
||||
<FormattedMessage
|
||||
id='post_body.check_for_out_of_channel_groups_mentions.message'
|
||||
defaultMessage='did not get notified by this mention because they are not in the channel. They cannot be added to the channel because they are not a member of the linked groups. To add them to this channel, they must be added to the linked groups.'
|
||||
/>
|
||||
);
|
||||
|
||||
messages.push(
|
||||
<p key='out-of-groups'>
|
||||
{outOfGroupsAtMentions}
|
||||
{' '}
|
||||
{outOfGroupsMessagePart}
|
||||
</p>
|
||||
</p>,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{outOfChannelMessage}
|
||||
{outOfGroupsMessage}
|
||||
{messages}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue