MM-28338 Fix Combined system messages (#22608)

* Web App -> Monorepo

* Update message data

* update snapshots

* update tests

* update tests, add null filter for userIds.

* Revert "update snapshots"

This reverts commit 4b3f5b192d.

* Remove not related tests

* Update post_list

* Update test (removing usernames for UserIds)

* Update webapp/channels/src/packages/mattermost-redux/src/utils/post_list.ts

better readability.

Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>

* remove unnecessary tests.

---------

Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Safouen Turki 2023-05-04 16:09:27 +01:00 committed by GitHub
parent 670b0e4c9f
commit fefca512c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 455 additions and 747 deletions

View File

@ -147,10 +147,10 @@ exports[`components/post_view/CombinedSystemMessage should match snapshot, "remo
</Fragment>
`;
exports[`components/post_view/CombinedSystemMessage should match snapshot, combining users removed from channel by all actors 1`] = `
exports[`components/post_view/CombinedSystemMessage should render messages in chronological order 1`] = `
<Fragment>
<Connect(Markdown)
message="@removed_username_1 and @removed_username_2 were **removed from the channel**."
message="@removed_username_1 was **removed from the channel**."
options={
Object {
"atMentions": true,
@ -159,64 +159,9 @@ exports[`components/post_view/CombinedSystemMessage should match snapshot, combi
Object {
"key": "@removed_username_1",
},
Object {
"key": "@removed_username_2",
},
Object {
"key": "you",
},
],
"singleline": true,
}
}
/>
<br />
</Fragment>
`;
exports[`components/post_view/CombinedSystemMessage should match snapshot, when current user is removed from then rejoined the channel 1`] = `
<Fragment>
<Connect(Markdown)
message="You **joined the channel**."
options={
Object {
"atMentions": true,
"mentionHighlight": false,
"mentionKeys": Array [
Object {
"key": "You",
},
Object {
"key": undefined,
},
Object {
"key": "",
},
],
"singleline": true,
}
}
/>
<br />
<injectIntl(LastUsers)
actor="you"
expandedLocale={
Object {
"defaultMessage": "{users} and {lastUser} were **removed from the channel**.",
"id": "combined_system_message.removed_from_channel.many_expanded",
}
}
formatOptions={
Object {
"atMentions": true,
"mentionHighlight": false,
"mentionKeys": Array [
Object {
"key": "You",
},
Object {
"key": "@removed_username_1",
},
Object {
"key": "you",
},
@ -224,13 +169,93 @@ exports[`components/post_view/CombinedSystemMessage should match snapshot, when
"singleline": true,
}
}
postType="system_remove_from_channel"
usernames={
Array [
"You",
"@removed_username_1",
"@removed_username_2",
]
/>
<br />
<Connect(Markdown)
message="@removed_username_2 **added to the channel** by Someone."
options={
Object {
"atMentions": true,
"mentionHighlight": false,
"mentionKeys": Array [
Object {
"key": "@removed_username_2",
},
Object {
"key": undefined,
},
Object {
"key": "Someone",
},
],
"singleline": true,
}
}
/>
<br />
<Connect(Markdown)
message="@removed_username_2 was **removed from the channel**."
options={
Object {
"atMentions": true,
"mentionHighlight": false,
"mentionKeys": Array [
Object {
"key": "@removed_username_2",
},
Object {
"key": undefined,
},
Object {
"key": "Someone",
},
],
"singleline": true,
}
}
/>
<br />
<Connect(Markdown)
message="@User2 **added to the channel** by @User1."
options={
Object {
"atMentions": true,
"mentionHighlight": false,
"mentionKeys": Array [
Object {
"key": "@User2",
},
Object {
"key": undefined,
},
Object {
"key": "@User1",
},
],
"singleline": true,
}
}
/>
<br />
<Connect(Markdown)
message="Someone **joined the channel**."
options={
Object {
"atMentions": true,
"mentionHighlight": false,
"mentionKeys": Array [
Object {
"key": "Someone",
},
Object {
"key": undefined,
},
Object {
"key": "Someone",
},
],
"singleline": true,
}
}
/>
<br />

View File

@ -61,25 +61,6 @@ describe('components/post_view/CombinedSystemMessage', () => {
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, combining users removed from channel by all actors', () => {
const allUserIds = ['current_user_id', 'other_user_id_1', 'removed_user_id_1', 'removed_user_id_2'];
const messageData = [{
actorId: 'current_user_id',
postType: Posts.POST_TYPES.REMOVE_FROM_CHANNEL,
userIds: ['removed_user_id_1'],
}, {
actorId: 'other_user_id_1',
postType: Posts.POST_TYPES.REMOVE_FROM_CHANNEL,
userIds: ['removed_user_id_2'],
}];
const props = {...baseProps, messageData, allUserIds};
const wrapper = shallowWithIntl(
<CombinedSystemMessage {...props}/>,
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot when join leave messages are turned off', () => {
const wrapper = shallowWithIntl(
<CombinedSystemMessage
@ -110,29 +91,6 @@ describe('components/post_view/CombinedSystemMessage', () => {
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, when current user is removed from then rejoined the channel', () => {
const allUserIds = ['current_user_id', 'other_user_id_1', 'removed_user_id_1', 'removed_user_id_2'];
const messageData = [{
actorId: '',
postType: Posts.POST_TYPES.JOIN_CHANNEL,
userIds: ['current_user_id'],
}, {
actorId: 'current_user_id',
postType: Posts.POST_TYPES.REMOVE_FROM_CHANNEL,
userIds: ['removed_user_id_1', 'removed_user_id_2'],
}, {
actorId: 'other_user_id_1',
postType: Posts.POST_TYPES.REMOVE_FROM_CHANNEL,
userIds: ['removed_user_id_2', 'current_user_id'],
}];
const props = {...baseProps, messageData, allUserIds};
const wrapper = shallowWithIntl(
<CombinedSystemMessage {...props}/>,
);
expect(wrapper).toMatchSnapshot();
});
test('should call getMissingProfilesByIds and/or getMissingProfilesByUsernames on loadUserProfiles', () => {
const props = {
...baseProps,
@ -164,4 +122,34 @@ describe('components/post_view/CombinedSystemMessage', () => {
expect(props.actions.getMissingProfilesByUsernames).toHaveBeenCalledTimes(1);
expect(props.actions.getMissingProfilesByUsernames).toHaveBeenCalledWith(['user1']);
});
test('should render messages in chronological order', () => {
const allUserIds = ['current_user_id', 'other_user_id_1', 'user_id_1', 'user_id_2', 'join_last'];
const messageData = [{
actorId: 'current_user_id',
postType: Posts.POST_TYPES.REMOVE_FROM_CHANNEL,
userIds: ['removed_user_id_1'],
}, {
actorId: 'other_user_id_1',
postType: Posts.POST_TYPES.ADD_TO_CHANNEL,
userIds: ['removed_user_id_2'],
}, {
actorId: 'other_user_id_1',
postType: Posts.POST_TYPES.REMOVE_FROM_CHANNEL,
userIds: ['removed_user_id_2'],
}, {
actorId: 'user_id_1',
postType: Posts.POST_TYPES.ADD_TO_CHANNEL,
userIds: ['user_id_2'],
}, {
actorId: 'join_last',
postType: Posts.POST_TYPES.JOIN_CHANNEL,
userIds: [''],
}];
const props = {...baseProps, messageData, allUserIds};
const wrapper = shallowWithIntl(
<CombinedSystemMessage {...props}/>,
);
expect(wrapper).toMatchSnapshot();
});
});

View File

@ -238,30 +238,32 @@ export class CombinedSystemMessage extends React.PureComponent<Props> {
return usernames;
};
getUsernamesByIds = (userIds: string[] = []): string[] => {
getUsernamesByIds = (userIds: string | string[] = []): string[] => {
const userIdsArray = Array.isArray(userIds) ? userIds : [userIds];
const {currentUserId, currentUsername} = this.props;
const allUsernames = this.getAllUsernames();
const {formatMessage} = this.props.intl;
const someone = formatMessage({id: t('channel_loader.someone'), defaultMessage: 'Someone'});
const usernames = userIds.
const usernames = userIdsArray.
filter((userId) => {
return userId !== currentUserId && userId !== currentUsername;
}).
map((userId) => {
return allUsernames[userId] ? `@${allUsernames[userId]}` : someone;
}).filter((username) => {
}).
filter((username) => {
return username && username !== '';
});
if (userIds.includes(currentUserId)) {
if (userIdsArray.includes(currentUserId)) {
usernames.unshift(allUsernames[currentUserId]);
} else if (userIds.includes(currentUsername)) {
} else if (userIdsArray.includes(currentUsername)) {
usernames.unshift(allUsernames[currentUsername]);
}
return usernames;
return Array.from(new Set(usernames));
};
renderFormattedMessage(postType: string, userIds: string[], actorId?: string): JSX.Element {
@ -328,7 +330,6 @@ export class CombinedSystemMessage extends React.PureComponent<Props> {
</React.Fragment>
);
}
render(): JSX.Element {
const {
currentUserId,
@ -336,7 +337,6 @@ export class CombinedSystemMessage extends React.PureComponent<Props> {
} = this.props;
const content = [];
const removedUserIds = [];
for (const message of messageData) {
const {
postType,
@ -356,19 +356,9 @@ export class CombinedSystemMessage extends React.PureComponent<Props> {
}
}
if (postType === REMOVE_FROM_CHANNEL) {
removedUserIds.push(...userIds);
continue;
}
content.push(this.renderMessage(postType, userIds, actorId));
}
if (removedUserIds.length > 0) {
const uniqueRemovedUserIds = removedUserIds.filter((id, index, arr) => arr.indexOf(id) === index);
content.push(this.renderMessage(REMOVE_FROM_CHANNEL, uniqueRemovedUserIds, currentUserId));
}
return (
<React.Fragment>
{content}

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {GlobalState} from '@mattermost/types/store';
import {Post} from '@mattermost/types/posts';
import {ActivityEntry, Post} from '@mattermost/types/posts';
import deepFreeze from 'mattermost-redux/utils/deep_freeze';
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
import {Posts, Preferences} from '../constants';
@ -11,7 +11,6 @@ import TestHelper from '../../test/test_helper';
import {
COMBINED_USER_ACTIVITY,
combineUserActivitySystemPost,
comparePostTypes,
DATE_LINE,
getDateForDateLine,
getFirstPostId,
@ -23,7 +22,7 @@ import {
makeCombineUserActivityPosts,
makeFilterPostsAndAddSeparators,
makeGenerateCombinedPost,
postTypePriority,
extractUserActivityData,
START_OF_NEW_MESSAGES,
} from './post_list';
@ -1014,8 +1013,11 @@ describe('makeGenerateCombinedPost', () => {
'bill joined the channel.',
],
user_activity: {
allUserIds: ['user2', 'user3', 'user1'],
allUsernames: [],
allUserIds: ['user1', 'user3', 'user2'],
allUsernames: [
'alice',
'joe',
],
messageData: [
{
postType: Posts.POST_TYPES.JOIN_CHANNEL,
@ -1023,18 +1025,18 @@ describe('makeGenerateCombinedPost', () => {
},
{
postType: Posts.POST_TYPES.ADD_TO_CHANNEL,
userIds: ['user2', 'user3'],
userIds: ['user3', 'user2'],
actorId: 'user1',
},
],
},
},
system_post_ids: ['post1', 'post2', 'post3'],
system_post_ids: ['post3', 'post2', 'post1'],
type: Posts.POST_TYPES.COMBINED_USER_ACTIVITY,
user_activity_posts: [
state.entities.posts.posts.post1,
state.entities.posts.posts.post2,
state.entities.posts.posts.post3,
state.entities.posts.posts.post2,
state.entities.posts.posts.post1,
],
user_id: '',
metadata: {},
@ -1109,7 +1111,7 @@ describe('makeGenerateCombinedPost', () => {
};
generateCombinedPost(state, initialCombinedId);
expect((generateCombinedPost as any).recomputations()).toBe(1);
expect((generateCombinedPost as any).recomputations()).toBe(2);
});
test('should recalculate when one of the included posts change', () => {
@ -1141,574 +1143,332 @@ describe('makeGenerateCombinedPost', () => {
});
});
});
const PostTypes = Posts.POST_TYPES;
describe('extractUserActivityData', () => {
const postAddToChannel: ActivityEntry = {
postType: PostTypes.ADD_TO_CHANNEL,
actorId: ['user_id_1'],
userIds: ['added_user_id_1'],
usernames: ['added_username_1'],
};
const postAddToTeam: ActivityEntry = {
postType: PostTypes.ADD_TO_TEAM,
actorId: ['user_id_1'],
userIds: ['added_user_id_1', 'added_user_id_2'],
usernames: ['added_username_1', 'added_username_2'],
};
const postLeaveChannel: ActivityEntry = {
postType: PostTypes.LEAVE_CHANNEL,
actorId: ['user_id_1'],
userIds: [],
usernames: [],
};
describe('combineUserActivitySystemPost', () => {
const PostTypes = Posts.POST_TYPES;
const postJoinChannel: ActivityEntry = {
postType: PostTypes.JOIN_CHANNEL,
actorId: ['user_id_1'],
userIds: [],
usernames: [],
};
it('should return null', () => {
expect(Boolean(combineUserActivitySystemPost())).toBe(false);
expect(Boolean(combineUserActivitySystemPost([]))).toBe(false);
const postRemoveFromChannel: ActivityEntry = {
postType: PostTypes.REMOVE_FROM_CHANNEL,
actorId: ['user_id_1'],
userIds: ['removed_user_id_1'],
usernames: ['removed_username_1'],
};
const postLeaveTeam: ActivityEntry = {
postType: PostTypes.LEAVE_TEAM,
actorId: ['user_id_1'],
userIds: [],
usernames: [],
};
const postJoinTeam: ActivityEntry = {
postType: PostTypes.JOIN_TEAM,
actorId: ['user_id_1'],
userIds: [],
usernames: [],
};
const postRemoveFromTeam: ActivityEntry = {
postType: PostTypes.REMOVE_FROM_TEAM,
actorId: ['user_id_1'],
userIds: [],
usernames: [],
};
it('should return empty activity when empty ', () => {
expect(extractUserActivityData([])).toEqual({allUserIds: [], allUsernames: [], messageData: []});
});
const postAddToChannel1 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_1', addedUsername: 'added_username_1'}});
const postAddToChannel2 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_2', addedUsername: 'added_username_2'}});
const postAddToChannel3 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_3', addedUsername: 'added_username_3'}});
const postAddToChannel4 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_2', props: {addedUserId: 'added_user_id_4', addedUsername: 'added_username_4'}});
const postAddToChannel5 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_1', props: {addedUsername: 'added_username_1'}});
it('should match return for ADD_TO_CHANNEL', () => {
const out1 = {
allUserIds: ['added_user_id_1', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1']}],
};
expect(combineUserActivitySystemPost([postAddToChannel1])).toEqual(out1);
const out2 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1', 'added_user_id_2']}],
};
expect(combineUserActivitySystemPost([postAddToChannel1, postAddToChannel2])).toEqual(out2);
const out3 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3']}],
};
expect(combineUserActivitySystemPost([postAddToChannel1, postAddToChannel2, postAddToChannel3])).toEqual(out3);
const out4 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3', 'user_id_1', 'added_user_id_4', 'user_id_2'],
allUsernames: [],
messageData: [
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3']},
{actorId: 'user_id_2', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_4']},
],
};
expect(combineUserActivitySystemPost([postAddToChannel1, postAddToChannel2, postAddToChannel3, postAddToChannel4])).toEqual(out4);
const out5 = {
allUserIds: ['user_id_1'],
allUsernames: ['added_username_1'],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_username_1']}],
};
expect(combineUserActivitySystemPost([postAddToChannel5])).toEqual(out5);
const out6 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3', 'user_id_1', 'added_user_id_4', 'user_id_2'],
allUsernames: ['added_username_1'],
messageData: [
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_username_1', 'added_user_id_1', 'added_user_id_2', 'added_user_id_3']},
{actorId: 'user_id_2', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_4']},
],
};
expect(combineUserActivitySystemPost([postAddToChannel1, postAddToChannel2, postAddToChannel3, postAddToChannel4, postAddToChannel5])).toEqual(out6);
});
it('should match return for ADD_TO_CHANNEL, backward compatibility with addedUsername', () => {
const out1 = {
allUserIds: ['user_id_1'],
allUsernames: ['added_user_name_1'],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_name_1']}],
};
expect(combineUserActivitySystemPost([{...postAddToChannel1, props: {addedUsername: 'added_user_name_1'}}])).toEqual(out1);
const out2 = {
allUserIds: ['added_user_id_2', 'user_id_1'],
allUsernames: ['added_user_name_1'],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_name_1', 'added_user_id_2']}],
};
expect(combineUserActivitySystemPost([{...postAddToChannel1, props: {addedUsername: 'added_user_name_1'}}, postAddToChannel2])).toEqual(out2);
const out3 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3', 'user_id_1', 'user_id_2'],
allUsernames: ['added_user_name_4'],
messageData: [
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3']},
{actorId: 'user_id_2', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_name_4']},
],
};
expect(combineUserActivitySystemPost([postAddToChannel1, postAddToChannel2, postAddToChannel3, {...postAddToChannel4, props: {addedUsername: 'added_user_name_4'}}])).toEqual(out3);
});
const postAddToTeam1 = TestHelper.getPostMock({type: PostTypes.ADD_TO_TEAM, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_1'}});
const postAddToTeam2 = TestHelper.getPostMock({type: PostTypes.ADD_TO_TEAM, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_2'}});
const postAddToTeam3 = TestHelper.getPostMock({type: PostTypes.ADD_TO_TEAM, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_3'}});
const postAddToTeam4 = TestHelper.getPostMock({type: PostTypes.ADD_TO_TEAM, user_id: 'user_id_2', props: {addedUserId: 'added_user_id_4'}});
it('should match return for ADD_TO_TEAM', () => {
const out1 = {
allUserIds: ['added_user_id_1', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_1']}],
};
expect(combineUserActivitySystemPost([postAddToTeam1])).toEqual(out1);
const out2 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_1', 'added_user_id_2']}],
};
expect(combineUserActivitySystemPost([postAddToTeam1, postAddToTeam2])).toEqual(out2);
const out3 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3']}],
};
expect(combineUserActivitySystemPost([postAddToTeam1, postAddToTeam2, postAddToTeam3])).toEqual(out3);
const out4 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3', 'user_id_1', 'added_user_id_4', 'user_id_2'],
allUsernames: [],
messageData: [
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3']},
{actorId: 'user_id_2', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_4']},
],
};
expect(combineUserActivitySystemPost([postAddToTeam1, postAddToTeam2, postAddToTeam3, postAddToTeam4])).toEqual(out4);
});
it('should match return for ADD_TO_TEAM, backward compatibility with addedUsername', () => {
const out1 = {
allUserIds: ['user_id_1'],
allUsernames: ['added_user_name_1'],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_name_1']}],
};
expect(combineUserActivitySystemPost([{...postAddToTeam1, props: {addedUsername: 'added_user_name_1'}}])).toEqual(out1);
const out2 = {
allUserIds: ['added_user_id_2', 'user_id_1'],
allUsernames: ['added_user_name_1'],
messageData: [{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_name_1', 'added_user_id_2']}],
};
expect(combineUserActivitySystemPost([{...postAddToTeam1, props: {addedUsername: 'added_user_name_1'}}, postAddToTeam2])).toEqual(out2);
const out3 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3', 'user_id_1', 'user_id_2'],
allUsernames: ['added_user_name_4'],
messageData: [
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3']},
{actorId: 'user_id_2', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_name_4']},
],
};
expect(combineUserActivitySystemPost([postAddToTeam1, postAddToTeam2, postAddToTeam3, {...postAddToTeam4, props: {addedUsername: 'added_user_name_4'}}])).toEqual(out3);
});
const postJoinChannel1 = TestHelper.getPostMock({type: PostTypes.JOIN_CHANNEL, user_id: 'user_id_1'});
const postJoinChannel2 = TestHelper.getPostMock({type: PostTypes.JOIN_CHANNEL, user_id: 'user_id_2'});
const postJoinChannel3 = TestHelper.getPostMock({type: PostTypes.JOIN_CHANNEL, user_id: 'user_id_3'});
const postJoinChannel4 = TestHelper.getPostMock({type: PostTypes.JOIN_CHANNEL, user_id: 'user_id_4'});
it('should match return for JOIN_CHANNEL', () => {
const out1 = {
const userActivities = [postJoinChannel];
const expectedOutput = {
allUserIds: ['user_id_1'],
allUsernames: [],
messageData: [{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1']}],
};
expect(combineUserActivitySystemPost([postJoinChannel1])).toEqual(out1);
const out2 = {
allUserIds: ['user_id_1', 'user_id_2'],
allUsernames: [],
messageData: [{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1', 'user_id_2']}],
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
const postJoinChannel2: ActivityEntry = {
postType: PostTypes.JOIN_CHANNEL,
actorId: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
userIds: [],
usernames: [],
};
expect(combineUserActivitySystemPost([postJoinChannel1, postJoinChannel2])).toEqual(out2);
const out3 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3'],
const expectedOutput2 = {
allUserIds: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
allUsernames: [],
messageData: [{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1', 'user_id_2', 'user_id_3']}],
messageData: [{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5']}],
};
expect(combineUserActivitySystemPost([postJoinChannel1, postJoinChannel2, postJoinChannel3])).toEqual(out3);
const out4 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4'],
allUsernames: [],
messageData: [{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4']}],
};
expect(combineUserActivitySystemPost([postJoinChannel1, postJoinChannel2, postJoinChannel3, postJoinChannel4])).toEqual(out4);
expect(extractUserActivityData([postJoinChannel2])).toEqual(expectedOutput2);
});
const postJoinTeam1 = TestHelper.getPostMock({type: PostTypes.JOIN_TEAM, user_id: 'user_id_1'});
const postJoinTeam2 = TestHelper.getPostMock({type: PostTypes.JOIN_TEAM, user_id: 'user_id_2'});
const postJoinTeam3 = TestHelper.getPostMock({type: PostTypes.JOIN_TEAM, user_id: 'user_id_3'});
const postJoinTeam4 = TestHelper.getPostMock({type: PostTypes.JOIN_TEAM, user_id: 'user_id_4'});
it('should match return for JOIN_TEAM', () => {
const out1 = {
it('should return expected data for ADD_TO_CHANNEL', () => {
const userActivities = [postAddToChannel];
const expectedOutput = {
allUserIds: ['added_user_id_1', 'user_id_1'],
allUsernames: ['added_username_1'],
messageData: [{postType: PostTypes.ADD_TO_CHANNEL, actorId: 'user_id_1', userIds: ['added_user_id_1']}],
};
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
const postAddToChannel2: ActivityEntry = {
postType: PostTypes.ADD_TO_CHANNEL,
actorId: ['user_id_2'],
userIds: ['added_user_id_2', 'added_user_id_3', 'added_user_id_4'],
usernames: ['added_username_2', 'added_username_3', 'added_username_4'],
};
const userActivities2 = [postAddToChannel, postAddToChannel2];
const expectedOutput2 = {
allUserIds: ['added_user_id_1', 'user_id_1', 'added_user_id_2', 'added_user_id_3', 'added_user_id_4', 'user_id_2'],
allUsernames: ['added_username_1', 'added_username_2', 'added_username_3', 'added_username_4'],
messageData: [
{postType: PostTypes.ADD_TO_CHANNEL, actorId: 'user_id_1', userIds: ['added_user_id_1']},
{postType: PostTypes.ADD_TO_CHANNEL, actorId: 'user_id_2', userIds: ['added_user_id_2', 'added_user_id_3', 'added_user_id_4']},
],
};
expect(extractUserActivityData(userActivities2)).toEqual(expectedOutput2);
});
it('should return expected data for ADD_TO_TEAM', () => {
const userActivities = [postAddToTeam];
const expectedOutput = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'user_id_1'],
allUsernames: ['added_username_1', 'added_username_2'],
messageData: [{postType: PostTypes.ADD_TO_TEAM, actorId: 'user_id_1', userIds: ['added_user_id_1', 'added_user_id_2']}],
};
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
const postAddToTeam2: ActivityEntry = {
postType: PostTypes.ADD_TO_TEAM,
actorId: ['user_id_2'],
userIds: ['added_user_id_3', 'added_user_id_4'],
usernames: ['added_username_3', 'added_username_4'],
};
const userActivities2 = [postAddToTeam, postAddToTeam2];
const expectedOutput2 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'user_id_1', 'added_user_id_3', 'added_user_id_4', 'user_id_2'],
allUsernames: ['added_username_1', 'added_username_2', 'added_username_3', 'added_username_4'],
messageData: [
{postType: PostTypes.ADD_TO_TEAM, actorId: 'user_id_1', userIds: ['added_user_id_1', 'added_user_id_2']},
{postType: PostTypes.ADD_TO_TEAM, actorId: 'user_id_2', userIds: ['added_user_id_3', 'added_user_id_4']},
],
};
expect(extractUserActivityData(userActivities2)).toEqual(expectedOutput2);
});
it('should return expected data for JOIN_TEAM', () => {
const userActivities = [postJoinTeam];
const expectedOutput = {
allUserIds: ['user_id_1'],
allUsernames: [],
messageData: [{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_1']}],
};
expect(combineUserActivitySystemPost([postJoinTeam1])).toEqual(out1);
const out2 = {
allUserIds: ['user_id_1', 'user_id_2'],
allUsernames: [],
messageData: [{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_1', 'user_id_2']}],
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
const postJoinTeam2: ActivityEntry = {
postType: PostTypes.JOIN_TEAM,
actorId: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
userIds: [],
usernames: [],
};
expect(combineUserActivitySystemPost([postJoinTeam1, postJoinTeam2])).toEqual(out2);
const out3 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3'],
const userActivities2 = [postJoinTeam, postJoinTeam2];
const expectedOutput2 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
allUsernames: [],
messageData: [{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_1', 'user_id_2', 'user_id_3']}],
messageData: [
{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_1']},
{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5']},
],
};
expect(combineUserActivitySystemPost([postJoinTeam1, postJoinTeam2, postJoinTeam3])).toEqual(out3);
const out4 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4'],
allUsernames: [],
messageData: [{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4']}],
};
expect(combineUserActivitySystemPost([postJoinTeam1, postJoinTeam2, postJoinTeam3, postJoinTeam4])).toEqual(out4);
expect(extractUserActivityData(userActivities2)).toEqual(expectedOutput2);
});
const postLeaveChannel1 = TestHelper.getPostMock({type: PostTypes.LEAVE_CHANNEL, user_id: 'user_id_1'});
const postLeaveChannel2 = TestHelper.getPostMock({type: PostTypes.LEAVE_CHANNEL, user_id: 'user_id_2'});
const postLeaveChannel3 = TestHelper.getPostMock({type: PostTypes.LEAVE_CHANNEL, user_id: 'user_id_3'});
const postLeaveChannel4 = TestHelper.getPostMock({type: PostTypes.LEAVE_CHANNEL, user_id: 'user_id_4'});
it('should match return for LEAVE_CHANNEL', () => {
const out1 = {
it('should return expected data for LEAVE_CHANNEL', () => {
const userActivities = [postLeaveChannel];
const expectedOutput = {
allUserIds: ['user_id_1'],
allUsernames: [],
messageData: [{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1']}],
};
expect(combineUserActivitySystemPost([postLeaveChannel1])).toEqual(out1);
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
const out2 = {
allUserIds: ['user_id_1', 'user_id_2'],
allUsernames: [],
messageData: [{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1', 'user_id_2']}],
const postLeaveChannel2: ActivityEntry = {
postType: PostTypes.LEAVE_CHANNEL,
actorId: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
userIds: [],
usernames: [],
};
expect(combineUserActivitySystemPost([postLeaveChannel1, postLeaveChannel2])).toEqual(out2);
const userActivities2 = [postLeaveChannel, postLeaveChannel2];
const expectedOutput2 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
allUsernames: [],
messageData: [
const out3 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3'],
allUsernames: [],
messageData: [{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1', 'user_id_2', 'user_id_3']}],
{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1']},
{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5']},
],
};
expect(combineUserActivitySystemPost([postLeaveChannel1, postLeaveChannel2, postLeaveChannel3])).toEqual(out3);
const out4 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4'],
allUsernames: [],
messageData: [{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4']}],
};
expect(combineUserActivitySystemPost([postLeaveChannel1, postLeaveChannel2, postLeaveChannel3, postLeaveChannel4])).toEqual(out4);
expect(extractUserActivityData(userActivities2)).toEqual(expectedOutput2);
});
const postLeaveTeam1 = TestHelper.getPostMock({type: PostTypes.LEAVE_TEAM, user_id: 'user_id_1'});
const postLeaveTeam2 = TestHelper.getPostMock({type: PostTypes.LEAVE_TEAM, user_id: 'user_id_2'});
const postLeaveTeam3 = TestHelper.getPostMock({type: PostTypes.LEAVE_TEAM, user_id: 'user_id_3'});
const postLeaveTeam4 = TestHelper.getPostMock({type: PostTypes.LEAVE_TEAM, user_id: 'user_id_4'});
it('should match return for LEAVE_TEAM', () => {
const out1 = {
it('should return expected data for LEAVE_TEAM', () => {
const userActivities = [postLeaveTeam];
const expectedOutput = {
allUserIds: ['user_id_1'],
allUsernames: [],
messageData: [{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_1']}],
};
expect(combineUserActivitySystemPost([postLeaveTeam1])).toEqual(out1);
const out2 = {
allUserIds: ['user_id_1', 'user_id_2'],
allUsernames: [],
messageData: [{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_1', 'user_id_2']}],
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
const postLeaveTeam2: ActivityEntry = {
postType: PostTypes.LEAVE_TEAM,
actorId: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
userIds: [],
usernames: [],
};
expect(combineUserActivitySystemPost([postLeaveTeam1, postLeaveTeam2])).toEqual(out2);
const out3 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3'],
const userActivities2 = [postLeaveTeam, postLeaveTeam2];
const expectedOutput2 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
allUsernames: [],
messageData: [{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_1', 'user_id_2', 'user_id_3']}],
messageData: [
{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_1']},
{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5']},
],
};
expect(combineUserActivitySystemPost([postLeaveTeam1, postLeaveTeam2, postLeaveTeam3])).toEqual(out3);
const out4 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4'],
allUsernames: [],
messageData: [{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4']}],
};
expect(combineUserActivitySystemPost([postLeaveTeam1, postLeaveTeam2, postLeaveTeam3, postLeaveTeam4])).toEqual(out4);
expect(extractUserActivityData(userActivities2)).toEqual(expectedOutput2);
});
const postRemoveFromChannel1 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_CHANNEL, user_id: 'user_id_1', props: {removedUserId: 'removed_user_id_1'}});
const postRemoveFromChannel2 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_CHANNEL, user_id: 'user_id_1', props: {removedUserId: 'removed_user_id_2'}});
const postRemoveFromChannel3 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_CHANNEL, user_id: 'user_id_1', props: {removedUserId: 'removed_user_id_3'}});
const postRemoveFromChannel4 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_CHANNEL, user_id: 'user_id_1', props: {removedUserId: 'removed_user_id_4'}});
it('should match return for REMOVE_FROM_CHANNEL', () => {
const out1 = {
it('should return expected data for REMOVE_FROM_CHANNEL', () => {
const userActivities = [postRemoveFromChannel];
const expectedOutput = {
allUserIds: ['removed_user_id_1', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.REMOVE_FROM_CHANNEL, userIds: ['removed_user_id_1']}],
allUsernames: ['removed_username_1'],
messageData: [{postType: PostTypes.REMOVE_FROM_CHANNEL, actorId: 'user_id_1', userIds: ['removed_user_id_1']}],
};
expect(combineUserActivitySystemPost([postRemoveFromChannel1])).toEqual(out1);
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
const out2 = {
allUserIds: ['removed_user_id_1', 'removed_user_id_2', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.REMOVE_FROM_CHANNEL, userIds: ['removed_user_id_1', 'removed_user_id_2']}],
const postRemoveFromChannel2: ActivityEntry = {
postType: PostTypes.REMOVE_FROM_CHANNEL,
actorId: ['user_id_2'],
userIds: ['removed_user_id_2', 'removed_user_id_3', 'removed_user_id_4', 'removed_user_id_5'],
usernames: ['removed_username_2', 'removed_username_3', 'removed_username_4', 'removed_username_5'],
};
expect(combineUserActivitySystemPost([postRemoveFromChannel1, postRemoveFromChannel2])).toEqual(out2);
const out3 = {
allUserIds: ['removed_user_id_1', 'removed_user_id_2', 'removed_user_id_3', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.REMOVE_FROM_CHANNEL, userIds: ['removed_user_id_1', 'removed_user_id_2', 'removed_user_id_3']}],
const userActivities2 = [postRemoveFromChannel, postRemoveFromChannel2];
const expectedOutput2 = {
allUserIds: ['removed_user_id_1', 'user_id_1', 'removed_user_id_2', 'removed_user_id_3', 'removed_user_id_4', 'removed_user_id_5', 'user_id_2'],
allUsernames: ['removed_username_1', 'removed_username_2', 'removed_username_3', 'removed_username_4', 'removed_username_5'],
messageData: [
{postType: PostTypes.REMOVE_FROM_CHANNEL, actorId: 'user_id_1', userIds: ['removed_user_id_1']},
{postType: PostTypes.REMOVE_FROM_CHANNEL, actorId: 'user_id_2', userIds: ['removed_user_id_2', 'removed_user_id_3', 'removed_user_id_4', 'removed_user_id_5']},
],
};
expect(combineUserActivitySystemPost([postRemoveFromChannel1, postRemoveFromChannel2, postRemoveFromChannel3])).toEqual(out3);
const out4 = {
allUserIds: ['removed_user_id_1', 'removed_user_id_2', 'removed_user_id_3', 'removed_user_id_4', 'user_id_1'],
allUsernames: [],
messageData: [{actorId: 'user_id_1', postType: PostTypes.REMOVE_FROM_CHANNEL, userIds: ['removed_user_id_1', 'removed_user_id_2', 'removed_user_id_3', 'removed_user_id_4']}],
};
expect(combineUserActivitySystemPost([postRemoveFromChannel1, postRemoveFromChannel2, postRemoveFromChannel3, postRemoveFromChannel4])).toEqual(out4);
expect(extractUserActivityData(userActivities2)).toEqual(expectedOutput2);
});
const postRemoveFromTeam1 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_TEAM, user_id: 'user_id_1'});
const postRemoveFromTeam2 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_TEAM, user_id: 'user_id_2'});
const postRemoveFromTeam3 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_TEAM, user_id: 'user_id_3'});
const postRemoveFromTeam4 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_TEAM, user_id: 'user_id_4'});
it('should match return for REMOVE_FROM_TEAM', () => {
const out1 = {
it('should return expected data for REMOVE_FROM_TEAM', () => {
const userActivities = [postRemoveFromTeam];
const expectedOutput = {
allUserIds: ['user_id_1'],
allUsernames: [],
messageData: [{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_1']}],
};
expect(combineUserActivitySystemPost([postRemoveFromTeam1])).toEqual(out1);
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
const out2 = {
allUserIds: ['user_id_1', 'user_id_2'],
allUsernames: [],
messageData: [{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_1', 'user_id_2']}],
const postRemoveFromTeam2: ActivityEntry = {
postType: PostTypes.REMOVE_FROM_TEAM,
actorId: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
userIds: [],
usernames: [],
};
expect(combineUserActivitySystemPost([postRemoveFromTeam1, postRemoveFromTeam2])).toEqual(out2);
const out3 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3'],
const userActivities2 = [postRemoveFromTeam, postRemoveFromTeam2];
const expectedOutput2 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4', 'user_id_5'],
allUsernames: [],
messageData: [{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_1', 'user_id_2', 'user_id_3']}],
messageData: [
{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_1']},
{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_2', 'user_id_3', 'user_id_4', 'user_id_5']},
],
};
expect(combineUserActivitySystemPost([postRemoveFromTeam1, postRemoveFromTeam2, postRemoveFromTeam3])).toEqual(out3);
const out4 = {
allUserIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4'],
allUsernames: [],
messageData: [{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4']}],
};
expect(combineUserActivitySystemPost([postRemoveFromTeam1, postRemoveFromTeam2, postRemoveFromTeam3, postRemoveFromTeam4])).toEqual(out4);
expect(extractUserActivityData(userActivities2)).toEqual(expectedOutput2);
});
it('should match return on combination', () => {
const out1 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'user_id_1'],
allUsernames: [],
it('should return expected data for multiple post types', () => {
const userActivities = [postAddToChannel, postAddToTeam, postJoinChannel, postJoinTeam, postLeaveChannel, postLeaveTeam, postRemoveFromChannel, postRemoveFromTeam];
const expectedOutput = {
allUserIds: ['added_user_id_1', 'user_id_1', 'added_user_id_2', 'removed_user_id_1'],
allUsernames: ['added_username_1', 'added_username_2', 'removed_username_1'],
messageData: [
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_1', 'added_user_id_2']},
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1', 'added_user_id_2']},
],
};
expect(combineUserActivitySystemPost([postAddToChannel1, postAddToChannel2, postAddToTeam1, postAddToTeam2])).toEqual(out1);
const out2 = {
allUserIds: ['user_id_1', 'user_id_2'],
allUsernames: [],
messageData: [
{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_1', 'user_id_2']},
{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1', 'user_id_2']},
],
};
expect(combineUserActivitySystemPost([postJoinChannel1, postJoinChannel2, postJoinTeam1, postJoinTeam2])).toEqual(out2);
const out3 = {
allUserIds: ['user_id_1', 'user_id_2'],
allUsernames: [],
messageData: [
{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_1', 'user_id_2']},
{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1', 'user_id_2']},
],
};
expect(combineUserActivitySystemPost([postLeaveChannel1, postLeaveChannel2, postLeaveTeam1, postLeaveTeam2])).toEqual(out3);
const out4 = {
allUserIds: ['removed_user_id_1', 'removed_user_id_2', 'user_id_1', 'user_id_2'],
allUsernames: [],
messageData: [
{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_1', 'user_id_2']},
{actorId: 'user_id_1', postType: PostTypes.REMOVE_FROM_CHANNEL, userIds: ['removed_user_id_1', 'removed_user_id_2']},
],
};
expect(combineUserActivitySystemPost([postRemoveFromChannel1, postRemoveFromChannel2, postRemoveFromTeam1, postRemoveFromTeam2])).toEqual(out4);
const out5 = {
allUserIds: ['added_user_id_1', 'added_user_id_2', 'user_id_1', 'user_id_2', 'removed_user_id_1', 'removed_user_id_2'],
allUsernames: [],
messageData: [
{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1', 'user_id_2']},
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1', 'added_user_id_2']},
{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1', 'user_id_2']},
{actorId: 'user_id_1', postType: PostTypes.REMOVE_FROM_CHANNEL, userIds: ['removed_user_id_1', 'removed_user_id_2']},
],
};
expect(combineUserActivitySystemPost([
postAddToChannel1,
postJoinChannel1,
postLeaveChannel1,
postRemoveFromChannel1,
postAddToChannel2,
postJoinChannel2,
postLeaveChannel2,
postRemoveFromChannel2,
])).toEqual(out5);
const out6 = {
allUserIds: ['added_user_id_3', 'user_id_1', 'added_user_id_4', 'user_id_2', 'user_id_3', 'user_id_4'],
allUsernames: [],
messageData: [
{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_3', 'user_id_4']},
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_3']},
{actorId: 'user_id_2', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_4']},
{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_3', 'user_id_4']},
{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_3', 'user_id_4']},
],
};
expect(combineUserActivitySystemPost([
postAddToTeam3,
postJoinTeam3,
postLeaveTeam3,
postRemoveFromTeam3,
postAddToTeam4,
postJoinTeam4,
postLeaveTeam4,
postRemoveFromTeam4,
])).toEqual(out6);
const out7 = {
allUserIds: ['added_user_id_3', 'added_user_id_1', 'added_user_id_2', 'user_id_1', 'added_user_id_4', 'user_id_2', 'user_id_3', 'user_id_4', 'removed_user_id_1', 'removed_user_id_2', 'removed_user_id_3', 'removed_user_id_4'],
allUsernames: [],
messageData: [
{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_3', 'user_id_4', 'user_id_1', 'user_id_2']},
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_3', 'added_user_id_1', 'added_user_id_2']},
{actorId: 'user_id_2', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_4']},
{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_3', 'user_id_4', 'user_id_1', 'user_id_2']},
{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_3', 'user_id_4', 'user_id_1', 'user_id_2']},
{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4']},
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1', 'added_user_id_2', 'added_user_id_3']},
{actorId: 'user_id_2', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_4']},
{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1', 'user_id_2', 'user_id_3', 'user_id_4']},
{actorId: 'user_id_1', postType: PostTypes.REMOVE_FROM_CHANNEL, userIds: ['removed_user_id_1', 'removed_user_id_2', 'removed_user_id_3', 'removed_user_id_4']},
],
};
expect(combineUserActivitySystemPost([
postAddToTeam3,
postJoinTeam3,
postLeaveTeam3,
postRemoveFromTeam3,
postAddToTeam4,
postJoinTeam4,
postLeaveTeam4,
postRemoveFromTeam4,
postAddToChannel1,
postJoinChannel1,
postLeaveChannel1,
postRemoveFromChannel1,
postAddToChannel2,
postJoinChannel2,
postLeaveChannel2,
postRemoveFromChannel2,
postAddToChannel3,
postJoinChannel3,
postLeaveChannel3,
postRemoveFromChannel3,
postAddToChannel4,
postJoinChannel4,
postLeaveChannel4,
postRemoveFromChannel4,
postAddToTeam1,
postJoinTeam1,
postLeaveTeam1,
postRemoveFromTeam1,
postAddToTeam2,
postJoinTeam2,
postLeaveTeam2,
postRemoveFromTeam2,
])).toEqual(out7);
const out8 = {
allUserIds: ['added_user_id_3', 'user_id_1', 'user_id_3', 'added_user_id_1', 'removed_user_id_1'],
allUsernames: [],
messageData: [
{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_3']},
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_TEAM, userIds: ['added_user_id_3']},
{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_3']},
{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_3']},
{postType: PostTypes.ADD_TO_CHANNEL, actorId: 'user_id_1', userIds: ['added_user_id_1']},
{postType: PostTypes.ADD_TO_TEAM, actorId: 'user_id_1', userIds: ['added_user_id_1', 'added_user_id_2']},
{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1']},
{actorId: 'user_id_1', postType: PostTypes.ADD_TO_CHANNEL, userIds: ['added_user_id_1']},
{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_1']},
{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1']},
{actorId: 'user_id_1', postType: PostTypes.REMOVE_FROM_CHANNEL, userIds: ['removed_user_id_1']},
{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_1']},
{postType: PostTypes.REMOVE_FROM_CHANNEL, actorId: 'user_id_1', userIds: ['removed_user_id_1']},
{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_1']},
],
};
expect(combineUserActivitySystemPost([
postAddToTeam3,
postAddToTeam3,
postJoinTeam3,
postJoinTeam3,
postLeaveTeam3,
postLeaveTeam3,
postRemoveFromTeam3,
postRemoveFromTeam3,
postAddToChannel1,
postAddToChannel1,
postJoinChannel1,
postJoinChannel1,
postLeaveChannel1,
postLeaveChannel1,
postRemoveFromChannel1,
postRemoveFromChannel1,
])).toEqual(out8);
expect(extractUserActivityData(userActivities)).toEqual(expectedOutput);
});
});
describe('comparePostTypes', () => {
const {
JOIN_TEAM,
ADD_TO_TEAM,
LEAVE_TEAM,
REMOVE_FROM_TEAM,
JOIN_CHANNEL,
ADD_TO_CHANNEL,
LEAVE_CHANNEL,
REMOVE_FROM_CHANNEL,
} = Posts.POST_TYPES;
const testCases = [
[],
[{postType: JOIN_TEAM}],
[{postType: JOIN_TEAM}, {postType: ADD_TO_TEAM}],
[{postType: ADD_TO_TEAM}, {postType: JOIN_TEAM}],
[{postType: ADD_TO_TEAM}, {postType: ADD_TO_TEAM}, {postType: JOIN_TEAM}],
[{postType: JOIN_TEAM}, {postType: ADD_TO_TEAM}, {postType: LEAVE_TEAM}, {postType: REMOVE_FROM_TEAM}],
[{postType: REMOVE_FROM_TEAM}, {postType: LEAVE_TEAM}, {postType: ADD_TO_TEAM}, {postType: JOIN_TEAM}],
[{postType: JOIN_CHANNEL}, {postType: ADD_TO_CHANNEL}, {postType: LEAVE_CHANNEL}, {postType: REMOVE_FROM_CHANNEL}],
[{postType: REMOVE_FROM_CHANNEL}, {postType: LEAVE_CHANNEL}, {postType: ADD_TO_CHANNEL}, {postType: JOIN_CHANNEL}],
[{postType: LEAVE_CHANNEL}, {postType: REMOVE_FROM_CHANNEL}, {postType: LEAVE_TEAM}, {postType: REMOVE_FROM_TEAM}],
[{postType: LEAVE_TEAM}, {postType: REMOVE_FROM_TEAM}, {postType: LEAVE_CHANNEL}, {postType: REMOVE_FROM_CHANNEL}],
[{postType: JOIN_CHANNEL}, {postType: LEAVE_CHANNEL}, {postType: JOIN_CHANNEL}, {postType: REMOVE_FROM_CHANNEL}, {postType: ADD_TO_CHANNEL}],
];
for (const testCase of testCases) {
let previousType = '';
testCase.sort(comparePostTypes as any).forEach((sortedTestCase, index) => {
it(`should sort post type correctly: ${previousType} should come first before ${sortedTestCase.postType}`, () => {
if (index > 0) {
expect(postTypePriority[previousType] <= postTypePriority[sortedTestCase.postType]).toBeTruthy();
}
previousType = sortedTestCase.postType;
describe('combineUserActivityData', () => {
it('combineUserActivitySystemPost returns null when systemPosts is an empty array', () => {
expect(combineUserActivitySystemPost([])).toBeNull();
});
it('correctly combine different post types and actorIds by order', () => {
const postAddToChannel1 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_1', addedUsername: 'added_username_1'}});
const postAddToTeam1 = TestHelper.getPostMock({type: PostTypes.ADD_TO_TEAM, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_1'}});
const postJoinChannel1 = TestHelper.getPostMock({type: PostTypes.JOIN_CHANNEL, user_id: 'user_id_1'});
const postJoinTeam1 = TestHelper.getPostMock({type: PostTypes.JOIN_TEAM, user_id: 'user_id_1'});
const postLeaveChannel1 = TestHelper.getPostMock({type: PostTypes.LEAVE_CHANNEL, user_id: 'user_id_1'});
const postLeaveTeam1 = TestHelper.getPostMock({type: PostTypes.LEAVE_TEAM, user_id: 'user_id_1'});
const postRemoveFromChannel1 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_CHANNEL, user_id: 'user_id_1', props: {removedUserId: 'removed_user_id_1', removedUsername: 'removed_username_1'}});
const postRemoveFromTeam1 = TestHelper.getPostMock({type: PostTypes.REMOVE_FROM_TEAM, user_id: 'user_id_1'});
const posts = [postAddToChannel1, postAddToTeam1, postJoinChannel1, postJoinTeam1, postLeaveChannel1, postLeaveTeam1, postRemoveFromChannel1, postRemoveFromTeam1].reverse();
const expectedOutput = {
allUserIds: ['added_user_id_1', 'user_id_1', 'removed_user_id_1'],
allUsernames: ['added_username_1', 'removed_username_1'],
messageData: [
{postType: PostTypes.ADD_TO_CHANNEL, actorId: 'user_id_1', userIds: ['added_user_id_1']},
{postType: PostTypes.ADD_TO_TEAM, actorId: 'user_id_1', userIds: ['added_user_id_1']},
{postType: PostTypes.JOIN_CHANNEL, userIds: ['user_id_1']},
{postType: PostTypes.JOIN_TEAM, userIds: ['user_id_1']},
{postType: PostTypes.LEAVE_CHANNEL, userIds: ['user_id_1']},
{postType: PostTypes.LEAVE_TEAM, userIds: ['user_id_1']},
{postType: PostTypes.REMOVE_FROM_CHANNEL, actorId: 'user_id_1', userIds: ['removed_user_id_1']},
{postType: PostTypes.REMOVE_FROM_TEAM, userIds: ['user_id_1']},
],
};
expect(combineUserActivitySystemPost(posts)).toEqual(expectedOutput);
});
it('correctly combine same post types', () => {
const postAddToChannel1 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_1', props: {addedUserId: 'added_user_id_1', addedUsername: 'added_username_1'}});
const postAddToChannel2 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_2', props: {addedUserId: 'added_user_id_2', addedUsername: 'added_username_2'}});
const postAddToChannel3 = TestHelper.getPostMock({type: PostTypes.ADD_TO_CHANNEL, user_id: 'user_id_3', props: {addedUserId: 'added_user_id_3', addedUsername: 'added_username_3'}});
const posts = [postAddToChannel1, postAddToChannel2, postAddToChannel3].reverse();
const expectedOutput = {
allUserIds: ['added_user_id_1', 'user_id_1', 'added_user_id_2', 'user_id_2', 'added_user_id_3', 'user_id_3'],
allUsernames: ['added_username_1', 'added_username_2', 'added_username_3'],
messageData: [
{postType: PostTypes.ADD_TO_CHANNEL, actorId: 'user_id_1', userIds: ['added_user_id_1']},
{postType: PostTypes.ADD_TO_CHANNEL, actorId: 'user_id_2', userIds: ['added_user_id_2']},
{postType: PostTypes.ADD_TO_CHANNEL, actorId: 'user_id_3', userIds: ['added_user_id_3']},
],
};
expect(combineUserActivitySystemPost(posts)).toEqual(expectedOutput);
});
}
});

View File

@ -16,7 +16,7 @@ import {createIdsSelector, memoizeResult} from 'mattermost-redux/utils/helpers';
import {isUserActivityPost, shouldFilterJoinLeavePost, isFromWebhook} from 'mattermost-redux/utils/post_utils';
import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils';
import {Post} from '@mattermost/types/posts';
import {ActivityEntry, Post} from '@mattermost/types/posts';
import {GlobalState} from '@mattermost/types/store';
export const COMBINED_USER_ACTIVITY = 'user-activity-';
@ -285,7 +285,6 @@ export function makeGenerateCombinedPost(): (state: GlobalState, combinedId: str
// Assume that the last post is the oldest one
const createAt = posts[posts.length - 1].create_at;
const messages = posts.map((post) => post.message);
return {
@ -323,66 +322,30 @@ export function makeGenerateCombinedPost(): (state: GlobalState, combinedId: str
);
}
export const postTypePriority = {
[Posts.POST_TYPES.JOIN_TEAM]: 0,
[Posts.POST_TYPES.ADD_TO_TEAM]: 1,
[Posts.POST_TYPES.LEAVE_TEAM]: 2,
[Posts.POST_TYPES.REMOVE_FROM_TEAM]: 3,
[Posts.POST_TYPES.JOIN_CHANNEL]: 4,
[Posts.POST_TYPES.ADD_TO_CHANNEL]: 5,
[Posts.POST_TYPES.LEAVE_CHANNEL]: 6,
[Posts.POST_TYPES.REMOVE_FROM_CHANNEL]: 7,
[Posts.POST_TYPES.PURPOSE_CHANGE]: 8,
[Posts.POST_TYPES.HEADER_CHANGE]: 9,
[Posts.POST_TYPES.JOIN_LEAVE]: 10,
[Posts.POST_TYPES.DISPLAYNAME_CHANGE]: 11,
[Posts.POST_TYPES.CONVERT_CHANNEL]: 12,
[Posts.POST_TYPES.CHANNEL_DELETED]: 13,
[Posts.POST_TYPES.CHANNEL_UNARCHIVED]: 14,
[Posts.POST_TYPES.ADD_REMOVE]: 15,
[Posts.POST_TYPES.EPHEMERAL]: 16,
};
export function comparePostTypes(a: typeof postTypePriority, b: typeof postTypePriority) {
return postTypePriority[a.postType] - postTypePriority[b.postType];
}
function extractUserActivityData(userActivities: any) {
export function extractUserActivityData(userActivities: ActivityEntry[]) {
const messageData: any[] = [];
const allUserIds: string[] = [];
const allUsernames: string[] = [];
Object.entries(userActivities).forEach(([postType, values]: [string, any]) => {
if (
postType === Posts.POST_TYPES.ADD_TO_TEAM ||
postType === Posts.POST_TYPES.ADD_TO_CHANNEL ||
postType === Posts.POST_TYPES.REMOVE_FROM_CHANNEL
) {
Object.keys(values).map((key) => [key, values[key]]).forEach(([actorId, users]) => {
if (Array.isArray(users)) {
throw new Error('Invalid Post activity data');
userActivities.forEach((activity) => {
if (isUsersRelatedPost(activity.postType)) {
const {postType, actorId, userIds, usernames} = activity;
if (usernames && userIds) {
messageData.push({postType, userIds: [...userIds], actorId: actorId[0]});
if (userIds.length > 0) {
allUserIds.push(...userIds.filter((userId) => userId));
}
const {ids, usernames} = users;
messageData.push({postType, userIds: [...usernames, ...ids], actorId});
if (ids.length > 0) {
allUserIds.push(...ids);
}
if (usernames.length > 0) {
allUsernames.push(...usernames);
allUsernames.push(...usernames.filter((username) => username));
}
allUserIds.push(actorId[0]);
}
allUserIds.push(actorId);
});
} else {
if (!Array.isArray(values)) {
throw new Error('Invalid Post activity data');
}
messageData.push({postType, userIds: values});
allUserIds.push(...values);
const {postType, actorId} = activity;
const userIds = actorId;
messageData.push({postType, userIds});
allUserIds.push(...userIds);
}
});
messageData.sort(comparePostTypes);
function reduceUsers(acc: string[], curr: string) {
if (!acc.includes(curr)) {
acc.push(curr);
@ -396,69 +359,45 @@ function extractUserActivityData(userActivities: any) {
messageData,
};
}
function isUsersRelatedPost(postType: string) {
return (
postType === Posts.POST_TYPES.ADD_TO_TEAM ||
postType === Posts.POST_TYPES.ADD_TO_CHANNEL ||
postType === Posts.POST_TYPES.REMOVE_FROM_CHANNEL
);
}
export function combineUserActivitySystemPost(systemPosts: Post[] = []) {
if (systemPosts.length === 0) {
return null;
}
const userActivities = systemPosts.reduce((acc: any, post: Post) => {
const userActivities: ActivityEntry[] = [];
systemPosts.reverse().forEach((post: Post) => {
const postType = post.type;
let userActivityProps = acc;
const combinedPostType = userActivityProps[postType as string];
const actorId = post.user_id;
if (
postType === Posts.POST_TYPES.ADD_TO_TEAM ||
postType === Posts.POST_TYPES.ADD_TO_CHANNEL ||
postType === Posts.POST_TYPES.REMOVE_FROM_CHANNEL
) {
const userId = post.props.addedUserId || post.props.removedUserId;
const username = post.props.addedUsername || post.props.removedUsername;
if (combinedPostType) {
if (Array.isArray(combinedPostType[post.user_id])) {
throw new Error('Invalid Post activity data');
}
const users = combinedPostType[post.user_id] || {ids: [], usernames: []};
if (userId) {
if (!users.ids.includes(userId)) {
users.ids.push(userId);
}
} else if (username && !users.usernames.includes(username)) {
users.usernames.push(username);
}
combinedPostType[post.user_id] = users;
// When combining removed posts, the actorId does not need to be the same for each post.
// All removed posts will be combined regardless of their respective actorIds.
const isRemovedPost = post.type === Posts.POST_TYPES.REMOVE_FROM_CHANNEL;
const userId = isUsersRelatedPost(postType) ? post.props.addedUserId || post.props.removedUserId : '';
const username = isUsersRelatedPost(postType) ? post.props.addedUsername || post.props.removedUsername : '';
const prevPost = userActivities[userActivities.length - 1];
const isSamePostType = prevPost && prevPost.postType === post.type;
const isSameActor = prevPost && prevPost.actorId[0] === post.user_id;
if (prevPost && isSamePostType && (isSameActor || isRemovedPost)) {
prevPost.userIds.push(userId);
prevPost.usernames.push(username);
} else if (isSamePostType && !isSameActor && !isUsersRelatedPost(postType)) {
prevPost.actorId.push(actorId);
} else {
const users = {
ids: [] as string[],
usernames: [] as string[],
};
if (userId) {
users.ids.push(userId);
} else if (username) {
users.usernames.push(username);
userActivities.push({
actorId: [actorId],
userIds: [userId],
usernames: [username],
postType,
});
}
userActivityProps[postType] = {
[post.user_id]: users,
};
}
} else {
const propsUserId = post.user_id;
if (combinedPostType) {
if (!Array.isArray(combinedPostType)) {
throw new Error('Invalid Post activity data');
}
if (!combinedPostType.includes(propsUserId)) {
userActivityProps[postType] = [...combinedPostType, propsUserId];
}
} else {
userActivityProps = {...userActivityProps, [postType]: [propsUserId]};
}
}
return userActivityProps;
}, {});
});
return extractUserActivityData(userActivities);
}

View File

@ -204,3 +204,9 @@ export type PostAnalytics = {
requested_ack?: boolean;
persistent_notifications?: boolean;
}
export type ActivityEntry = {
postType: Post['type'];
actorId: string[];
userIds: string[];
usernames: string[];
}