[MM-54933] Add the ability to @ mention custom groups in group constrained teams and channels (#24987)
* add the ability to @ mention custom groups in group constrained teams --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
@@ -1151,6 +1151,18 @@ func (a *App) getGroupsAllowedForReferenceInChannel(channel *model.Channel, team
|
|||||||
groupsMap[group.Id] = &group.Group
|
groupsMap[group.Id] = &group.Group
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opts.Source = model.GroupSourceCustom
|
||||||
|
var customgroups []*model.Group
|
||||||
|
customgroups, err = a.Srv().Store().Group().GetGroups(0, 0, opts, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "unable to get custom groups")
|
||||||
|
}
|
||||||
|
for _, group := range customgroups {
|
||||||
|
if group.Name != nil {
|
||||||
|
groupsMap[group.Id] = group
|
||||||
|
}
|
||||||
|
}
|
||||||
return groupsMap, nil
|
return groupsMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2571,6 +2571,25 @@ func TestGetGroupsAllowedForReferenceInChannel(t *testing.T) {
|
|||||||
group2, err = th.App.UpdateGroup(group2)
|
group2, err = th.App.UpdateGroup(group2)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
// Create a custom group
|
||||||
|
customGroupId := model.NewId()
|
||||||
|
customGroup, err := th.App.CreateGroup(&model.Group{
|
||||||
|
DisplayName: customGroupId,
|
||||||
|
Name: model.NewString("name" + customGroupId),
|
||||||
|
Source: model.GroupSourceCustom,
|
||||||
|
Description: "description_" + customGroupId,
|
||||||
|
AllowReference: true,
|
||||||
|
RemoteId: nil,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
u1 := th.BasicUser
|
||||||
|
_, err = th.App.UpsertGroupMember(customGroup.Id, u1.Id)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
customGroup, err = th.App.GetGroup(customGroup.Id, &model.GetGroupOpts{IncludeMemberCount: true}, nil)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// Sync first group to constrained channel
|
// Sync first group to constrained channel
|
||||||
constrainedChannel := th.CreateChannel(th.Context, th.BasicTeam)
|
constrainedChannel := th.CreateChannel(th.Context, th.BasicTeam)
|
||||||
constrainedChannel.GroupConstrained = model.NewBool(true)
|
constrainedChannel.GroupConstrained = model.NewBool(true)
|
||||||
@@ -2583,15 +2602,16 @@ func TestGetGroupsAllowedForReferenceInChannel(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
t.Run("should return only groups synced to channel if channel is group constrained", func(t *testing.T) {
|
t.Run("should return only groups synced to channel and custom groups if channel is group constrained", func(t *testing.T) {
|
||||||
groupsMap, nErr := th.App.getGroupsAllowedForReferenceInChannel(constrainedChannel, team)
|
groupsMap, nErr := th.App.getGroupsAllowedForReferenceInChannel(constrainedChannel, team)
|
||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
require.Len(t, groupsMap, 1)
|
require.Len(t, groupsMap, 2)
|
||||||
require.Nil(t, groupsMap[group2.Id])
|
require.Nil(t, groupsMap[group2.Id])
|
||||||
require.Equal(t, groupsMap[group1.Id], group1)
|
require.Equal(t, groupsMap[group1.Id], group1)
|
||||||
|
require.Equal(t, groupsMap[customGroup.Id], customGroup)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create a third group not synced with a team or channel
|
// Create a third ldap group not synced with a team or channel
|
||||||
group3 := th.CreateGroup()
|
group3 := th.CreateGroup()
|
||||||
group3.AllowReference = true
|
group3.AllowReference = true
|
||||||
group3, err = th.App.UpdateGroup(group3)
|
group3, err = th.App.UpdateGroup(group3)
|
||||||
@@ -2608,22 +2628,24 @@ func TestGetGroupsAllowedForReferenceInChannel(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
t.Run("should return union of groups synced to team and any channels if team is group constrained", func(t *testing.T) {
|
t.Run("should return union of custom groups, groups synced to team and any channels if team is group constrained", func(t *testing.T) {
|
||||||
groupsMap, nErr := th.App.getGroupsAllowedForReferenceInChannel(channel, team)
|
groupsMap, nErr := th.App.getGroupsAllowedForReferenceInChannel(channel, team)
|
||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
require.Len(t, groupsMap, 2)
|
require.Len(t, groupsMap, 3)
|
||||||
require.Nil(t, groupsMap[group3.Id])
|
require.Nil(t, groupsMap[group3.Id])
|
||||||
require.Equal(t, groupsMap[group2.Id], group2)
|
require.Equal(t, groupsMap[group2.Id], group2)
|
||||||
require.Equal(t, groupsMap[group1.Id], group1)
|
require.Equal(t, groupsMap[group1.Id], group1)
|
||||||
|
require.Equal(t, groupsMap[customGroup.Id], customGroup)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should return only subset of groups synced to channel for group constrained channel when team is also group constrained", func(t *testing.T) {
|
t.Run("should return only subset of custom groups and groups synced to channel for group constrained channel when team is also group constrained", func(t *testing.T) {
|
||||||
groupsMap, nErr := th.App.getGroupsAllowedForReferenceInChannel(constrainedChannel, team)
|
groupsMap, nErr := th.App.getGroupsAllowedForReferenceInChannel(constrainedChannel, team)
|
||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
require.Len(t, groupsMap, 1)
|
require.Len(t, groupsMap, 2)
|
||||||
require.Nil(t, groupsMap[group3.Id])
|
require.Nil(t, groupsMap[group3.Id])
|
||||||
require.Nil(t, groupsMap[group2.Id])
|
require.Nil(t, groupsMap[group2.Id])
|
||||||
require.Equal(t, groupsMap[group1.Id], group1)
|
require.Equal(t, groupsMap[group1.Id], group1)
|
||||||
|
require.Equal(t, groupsMap[customGroup.Id], customGroup)
|
||||||
})
|
})
|
||||||
|
|
||||||
team.GroupConstrained = model.NewBool(false)
|
team.GroupConstrained = model.NewBool(false)
|
||||||
@@ -2633,10 +2655,11 @@ func TestGetGroupsAllowedForReferenceInChannel(t *testing.T) {
|
|||||||
t.Run("should return all groups when team and channel are not group constrained", func(t *testing.T) {
|
t.Run("should return all groups when team and channel are not group constrained", func(t *testing.T) {
|
||||||
groupsMap, nErr := th.App.getGroupsAllowedForReferenceInChannel(channel, team)
|
groupsMap, nErr := th.App.getGroupsAllowedForReferenceInChannel(channel, team)
|
||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
require.Len(t, groupsMap, 3)
|
require.Len(t, groupsMap, 4)
|
||||||
require.Equal(t, groupsMap[group1.Id], group1)
|
require.Equal(t, groupsMap[group1.Id], group1)
|
||||||
require.Equal(t, groupsMap[group2.Id], group2)
|
require.Equal(t, groupsMap[group2.Id], group2)
|
||||||
require.Equal(t, groupsMap[group3.Id], group3)
|
require.Equal(t, groupsMap[group3.Id], group3)
|
||||||
|
require.Equal(t, groupsMap[customGroup.Id], customGroup)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ describe('Selectors.Groups', () => {
|
|||||||
},
|
},
|
||||||
teams: {
|
teams: {
|
||||||
teams: {
|
teams: {
|
||||||
[teamID]: {group_constrained: false},
|
[teamID]: {group_constrained: true, id: teamID},
|
||||||
},
|
},
|
||||||
groupsAssociatedToTeam: {
|
groupsAssociatedToTeam: {
|
||||||
[teamID]: {ids: teamAssociatedGroupIDs},
|
[teamID]: {ids: teamAssociatedGroupIDs},
|
||||||
@@ -129,7 +129,7 @@ describe('Selectors.Groups', () => {
|
|||||||
},
|
},
|
||||||
channels: {
|
channels: {
|
||||||
channels: {
|
channels: {
|
||||||
[channelID]: {team_id: teamID, id: channelID},
|
[channelID]: {team_id: teamID, id: channelID, group_constrained: true},
|
||||||
},
|
},
|
||||||
groupsAssociatedToChannel: {
|
groupsAssociatedToChannel: {
|
||||||
[channelID]: {ids: channelAssociatedGroupIDs},
|
[channelID]: {ids: channelAssociatedGroupIDs},
|
||||||
@@ -242,4 +242,38 @@ describe('Selectors.Groups', () => {
|
|||||||
];
|
];
|
||||||
expect(Selectors.getMyGroupMentionKeysForChannel(testState, teamID, channelID)).toEqual(expected);
|
expect(Selectors.getMyGroupMentionKeysForChannel(testState, teamID, channelID)).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('getAssociatedGroupsForReference team constrained', () => {
|
||||||
|
const expected = [
|
||||||
|
group5,
|
||||||
|
group1,
|
||||||
|
];
|
||||||
|
expect(Selectors.getAssociatedGroupsForReference(testState, teamID, '')).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getAssociatedGroupsForReference channel constrained', () => {
|
||||||
|
const expected = [
|
||||||
|
group5,
|
||||||
|
group4,
|
||||||
|
];
|
||||||
|
expect(Selectors.getAssociatedGroupsForReference(testState, '', channelID)).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getAssociatedGroupsForReference team and channel constrained', () => {
|
||||||
|
const expected = [
|
||||||
|
group4,
|
||||||
|
group1,
|
||||||
|
group5,
|
||||||
|
];
|
||||||
|
expect(Selectors.getAssociatedGroupsForReference(testState, teamID, channelID)).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getAssociatedGroupsForReference no constraints', () => {
|
||||||
|
const expected = [
|
||||||
|
group1,
|
||||||
|
group4,
|
||||||
|
group5,
|
||||||
|
];
|
||||||
|
expect(Selectors.getAssociatedGroupsForReference(testState, '', '')).toEqual(expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -125,11 +125,16 @@ export function getAssociatedGroupsForReference(state: GlobalState, teamId: stri
|
|||||||
if (team && team.group_constrained && channel && channel.group_constrained) {
|
if (team && team.group_constrained && channel && channel.group_constrained) {
|
||||||
const groupsFromChannel = getGroupsAssociatedToChannelForReference(state, channelId);
|
const groupsFromChannel = getGroupsAssociatedToChannelForReference(state, channelId);
|
||||||
const groupsFromTeam = getGroupsAssociatedToTeamForReference(state, teamId);
|
const groupsFromTeam = getGroupsAssociatedToTeamForReference(state, teamId);
|
||||||
groupsForReference = groupsFromChannel.concat(groupsFromTeam.filter((item) => groupsFromChannel.indexOf(item) < 0));
|
const customGroups = getAllCustomGroups(state);
|
||||||
|
groupsForReference = groupsFromChannel.concat(groupsFromTeam.filter((item) => groupsFromChannel.indexOf(item) < 0), customGroups);
|
||||||
} else if (team && team.group_constrained) {
|
} else if (team && team.group_constrained) {
|
||||||
groupsForReference = getGroupsAssociatedToTeamForReference(state, teamId);
|
const customGroups = getAllCustomGroups(state);
|
||||||
|
const groupsFromTeam = getGroupsAssociatedToTeamForReference(state, teamId);
|
||||||
|
groupsForReference = [...customGroups, ...groupsFromTeam];
|
||||||
} else if (channel && channel.group_constrained) {
|
} else if (channel && channel.group_constrained) {
|
||||||
groupsForReference = getGroupsAssociatedToChannelForReference(state, channelId);
|
const customGroups = getAllCustomGroups(state);
|
||||||
|
const groupsFromChannel = getGroupsAssociatedToChannelForReference(state, channelId);
|
||||||
|
groupsForReference = [...customGroups, ...groupsFromChannel];
|
||||||
} else {
|
} else {
|
||||||
groupsForReference = getAllAssociatedGroupsForReference(state, false);
|
groupsForReference = getAllAssociatedGroupsForReference(state, false);
|
||||||
}
|
}
|
||||||
@@ -259,6 +264,14 @@ export const getAllGroupsForReferenceByName: (state: GlobalState) => Record<stri
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getAllCustomGroups: (state: GlobalState) => Group[] = createSelector(
|
||||||
|
'getAllCustomGroups',
|
||||||
|
getAllGroups,
|
||||||
|
(groups) => {
|
||||||
|
return Object.entries(groups).filter((entry) => (entry[1].allow_reference && entry[1].delete_at === 0 && entry[1].source === GroupSource.Custom)).map((entry) => entry[1]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const makeGetMyAllowReferencedGroups = () => {
|
export const makeGetMyAllowReferencedGroups = () => {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
'makeGetMyAllowReferencedGroups',
|
'makeGetMyAllowReferencedGroups',
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user